<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>小波的博客 | 小波的博客</title><meta name="author" content="Steve"><meta name="copyright" content="Steve"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="1.MySQL 环境1.1.环境安装1234567891011121314151617181920212223242526272829303132333435363738394041424344454647# 查看 Linux 服务器上是否安装过 MySQLrpm -qa | grep -i mysql # 查询出所有 mysql 依赖包# 1、拉取镜像docker pull mysql:5.7#">
<meta property="og:type" content="article">
<meta property="og:title" content="小波的博客">
<meta property="og:url" content="https://steve6636.gitee.io/2021/10/24/MySQL_%E5%91%A8%E9%98%B3%202018%20%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0_20210405/index.html">
<meta property="og:site_name" content="小波的博客">
<meta property="og:description" content="1.MySQL 环境1.1.环境安装1234567891011121314151617181920212223242526272829303132333435363738394041424344454647# 查看 Linux 服务器上是否安装过 MySQLrpm -qa | grep -i mysql # 查询出所有 mysql 依赖包# 1、拉取镜像docker pull mysql:5.7#">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg">
<meta property="article:published_time" content="2021-10-24T14:29:22.971Z">
<meta property="article:modified_time" content="2021-10-24T14:28:51.435Z">
<meta property="article:author" content="Steve">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="https://steve6636.gitee.io/2021/10/24/MySQL_%E5%91%A8%E9%98%B3%202018%20%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0_20210405/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"search.xml","languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'mediumZoom',
  Snackbar: undefined,
  source: {
    jQuery: 'https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js',
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/js/jquery.justifiedGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/css/justifiedGallery.min.css'
    },
    fancybox: {
      js: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js',
      css: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: true,
  isanchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = { 
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2021-10-24 22:28:51'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const fontSizeVal = saveToLocal.get('global-font-size')
    if (fontSizeVal !== undefined) {
      document.documentElement.style.setProperty('--global-font-size', fontSizeVal + 'px')
    }
    })(window)</script><meta name="generator" content="Hexo 5.4.0"><link rel="alternate" href="/atom.xml" title="小波的博客" type="application/atom+xml">
</head><body><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="author-avatar"><img class="avatar-img" data-lazy-src="https://gitee.com/forkiller/picture/raw/master/img/20210327175316.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data"><div class="data-item is-center"><div class="data-item-link"><a href="/archives/"><div class="headline">文章</div><div class="length-num">26</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/tags/"><div class="headline">标签</div><div class="length-num">11</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/categories/"><div class="headline">分类</div><div class="length-num">9</div></a></div></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> Link</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于我</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 工具箱</span></a></div><div class="menus_item"><a class="site-page" href="/friends"><i class="fa-fw fas fa-address-book"></i><span> Friends</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">小波的博客</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> Link</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于我</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 工具箱</span></a></div><div class="menus_item"><a class="site-page" href="/friends"><i class="fa-fw fas fa-address-book"></i><span> Friends</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">无题</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2021-10-24T14:29:22.971Z" title="发表于 2021-10-24 22:29:22">2021-10-24</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2021-10-24T14:28:51.435Z" title="更新于 2021-10-24 22:28:51">2021-10-24</time></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">20.6k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>82分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="1-MySQL-环境"><a href="#1-MySQL-环境" class="headerlink" title="1.MySQL 环境"></a>1.MySQL 环境</h1><h2 id="1-1-环境安装"><a href="#1-1-环境安装" class="headerlink" title="1.1.环境安装"></a>1.1.环境安装</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 查看 Linux 服务器上是否安装过 MySQL</span></span><br><span class="line">rpm -qa | grep -i mysql # 查询出所有 mysql 依赖包</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 1、拉取镜像</span></span><br><span class="line">docker pull mysql:5.7</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 2、创建实例并启动</span></span><br><span class="line">docker run -p 3306:3306 --name mysql \</span><br><span class="line">-v /root/mysql/log:/var/log/mysql \</span><br><span class="line">-v /root/mysql/data:/var/lib/mysql \</span><br><span class="line">-v /root/mysql/conf:/etc/mysql \</span><br><span class="line">-e MYSQL_ROOT_PASSWORD=333 \</span><br><span class="line">-d mysql:5.7</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 3、mysql配置 /root/mysql/conf/my.conf</span></span><br><span class="line">[client]</span><br><span class="line"><span class="meta">#</span><span class="bash"> mysqlde utf8 字符集默认为 3 位的，不支持 emoji 表情及部分不常见的汉字，故推荐使用 utf8mb4</span></span><br><span class="line">default-character-set=utf8</span><br><span class="line"></span><br><span class="line">[mysql]</span><br><span class="line">default-character-set=utf8</span><br><span class="line"></span><br><span class="line">[mysqld]</span><br><span class="line"><span class="meta">#</span><span class="bash"> 设置 client 连接 mysql 时的字符集,防止乱码</span></span><br><span class="line">init_connect=&#x27;SET collation_connection = utf8_general_ci&#x27;</span><br><span class="line">init_connect=&#x27;SET NAMES utf8&#x27;</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 数据库默认字符集</span></span><br><span class="line">character-set-server=utf8</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 数据库字符集对应一些排序等规则，注意要和 character-set-server对应</span></span><br><span class="line">collation-server=utf8_general_ci</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 跳过 mysql 程序起动时的字符参数设置 ，使用服务器端字符集设置</span></span><br><span class="line">skip-character-set-client-handshake</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 禁止 MySQL 对外部连接进行 DNS 解析，使用这一选项可以消除 MySQL 进行 DNS 解析的时间。但需要注意，如果开启该选项，则所有远程主机连接授权都要使用 IP 地址方式，否则 MySQL 将无法正常处理连接请求！</span></span><br><span class="line">skip-name-resolve</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 4、重启 mysql 容器</span></span><br><span class="line">docker restart mysql</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 5、进入到 mysql 容器</span></span><br><span class="line">docker exec -it mysql /bin/bash</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 6、查看修改的配置文件</span></span><br><span class="line">cat /etc/mysql/my.conf</span><br></pre></td></tr></table></figure>

<h2 id="1-2-安装位置"><a href="#1-2-安装位置" class="headerlink" title="1.2.安装位置"></a>1.2.安装位置</h2><p><code>Docker</code>容器就是一个小型的<code>Linux</code>环境，进入到<code>MySQL</code>容器中。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker exec -it mysql /bin/bash</span><br></pre></td></tr></table></figure>

<p><code>Linux</code>环境下<code>MySQL</code>的安装目录。</p>
<table>
<thead>
<tr>
<th>路径</th>
<th>解释</th>
</tr>
</thead>
<tbody><tr>
<td><code>/var/lib/mysql</code></td>
<td>MySQL 数据库文件存放位置</td>
</tr>
<tr>
<td><code>/usr/share/mysql</code></td>
<td>错误消息和字符集文件配置</td>
</tr>
<tr>
<td><code>/usr/bin</code></td>
<td>客户端程序和脚本</td>
</tr>
<tr>
<td><code>/etc/init.d/mysql</code></td>
<td>启停脚本相关</td>
</tr>
</tbody></table>
<h2 id="1-3-修改字符集"><a href="#1-3-修改字符集" class="headerlink" title="1.3.修改字符集"></a>1.3.修改字符集</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1、进入到 mysql 数据库并查看字符集</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> show variables like <span class="string">&#x27;character%&#x27;</span>;</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> show variables like <span class="string">&#x27;%char%&#x27;</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> show variables like <span class="string">&#x27;character%&#x27;</span>;</span></span><br><span class="line">+--------------------------+----------------------------+</span><br><span class="line">| Variable_name            | Value                      |</span><br><span class="line">+--------------------------+----------------------------+</span><br><span class="line">| character_set_client     | utf8                       |</span><br><span class="line">| character_set_connection | utf8                       |</span><br><span class="line">| character_set_database   | utf8                       |</span><br><span class="line">| character_set_filesystem | binary                     |</span><br><span class="line">| character_set_results    | utf8                       |</span><br><span class="line">| character_set_server     | utf8                       |</span><br><span class="line">| character_set_system     | utf8                       |</span><br><span class="line">| character_sets_dir       | /usr/share/mysql/charsets/ |</span><br><span class="line">+--------------------------+----------------------------+</span><br><span class="line">8 rows in set (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> show variables like <span class="string">&#x27;%char%&#x27;</span>;</span></span><br><span class="line">+--------------------------+----------------------------+</span><br><span class="line">| Variable_name         | Value               |</span><br><span class="line">+--------------------------+----------------------------+</span><br><span class="line">| character_set_client     | utf8              |</span><br><span class="line">| character_set_connection  | utf8               |</span><br><span class="line">| character_set_database   | utf8               |</span><br><span class="line">| character_set_filesyste m | binary              |</span><br><span class="line">| character_set_results    | utf8               |</span><br><span class="line">| character_set_server     | utf8               |</span><br><span class="line">| character_set_system     | utf8               |</span><br><span class="line">| character_sets_dir       | /usr/share/mysql/charsets/ |</span><br><span class="line">+--------------------------+----------------------------+</span><br><span class="line">8 rows in set (0.01 sec)</span><br></pre></td></tr></table></figure>



<p><code>MySQL5.7</code>配置文件位置是<code>/etc/my.cnf</code>或者<code>/etc/mysql/my.cnf</code>，如果字符集不是<code>utf-8</code>直接进入配置文件修改即可。</p>
<p>docker mysql 修改配置文件：</p>
<ol>
<li><p>下载完成之后 ，输入 docker ps 查看镜像</p>
</li>
<li><p>启动容器：<code>docker run -p 3307:3306 --name mysql -e MYSQL_ROOT_PASSWORD=root -d mysql</code> ，<code>docker ps</code> 可以查看状态</p>
</li>
<li><p>进入 MySQL 容器内：<code>docker exec -it 容器名 /bin/bash</code> （PS：其实这个跟 Linux 修改文件一样，有好多方法，我用的是最笨的一种。）将本地文件替换容器文件</p>
</li>
<li><p>我这里要修改的是 MySQL 里面的 <code>my.cnf </code>文件。可先用 ls 查看目录文件。</p>
</li>
<li><p><code>tail my.cnf</code> （PS：tail 命令可用于查看文件的内容）</p>
</li>
<li><p>运行 vim 代码</p>
</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># 先备份配置文件</span><br><span class="line">cp .my.cnf .&#x2F;my.cnf.bak</span><br><span class="line"># 编辑配置文件</span><br><span class="line">vim &#x2F;etc&#x2F;mysql&#x2F;my.cnf</span><br></pre></td></tr></table></figure>

<ol start="7">
<li><p>运行上述 vim 代码之后可能会发现没有执行成功，因为 docker 容器中没有 vim 编辑器，所以要自己安装 vim 编辑器（vim 安装方法详情可见文章末尾附录）</p>
</li>
<li><p>进入 my.cnf 文件，添加以下内容</p>
</li>
</ol>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">[client]</span><br><span class="line">default-character-set=utf8</span><br><span class="line"></span><br><span class="line">[mysql]</span><br><span class="line">default-character-set=utf8</span><br><span class="line"></span><br><span class="line">[mysqld]</span><br><span class="line"><span class="meta">#</span><span class="bash"> 设置 client 连接 mysql 时的字符集,防止乱码</span></span><br><span class="line">init_connect=&#x27;SET NAMES utf8&#x27;</span><br><span class="line">init_connect=&#x27;SET collation_connection = utf8_general_ci&#x27;</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 数据库默认字符集</span></span><br><span class="line">character-set-server=utf8</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">数据库字符集对应一些排序等规则，注意要和 character-set-server 对应</span></span><br><span class="line">collation-server=utf8_general_ci</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 跳过 mysql 程序起动时的字符参数设置 ，使用服务器端字符集设置</span></span><br><span class="line">skip-character-set-client-handshake</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 禁止 MySQL 对外部连接进行DNS解析，使用这一选项可以消除 MySQL 进行 DNS 解析的时间。但需要注意，如果开启该选项，则所有远程主机连接授权都要使用 IP 地址方式，否则 MySQL 将无法正常处理连接请求！</span></span><br><span class="line">skip-name-resolve</span><br></pre></td></tr></table></figure>

<p><strong>注意：安装<code>MySQL</code>完毕之后，第一件事就是修改字符集编码。</strong></p>
<p>这里的 utf8mb4 和 utf8 差别不大。因为一些历史遗留问题，导致 mysql 当中的 utf8 并不是通用标准的 utf8，在极少数情况下会出现编码不统一的问题 utf8mb4 才是 MySQL 中提供的通用 utf8 编码标准，严谨起见，建议在 MySQL 中统一设置为 utf8mb4</p>
<h2 id="1-4-配置文件"><a href="#1-4-配置文件" class="headerlink" title="1.4.配置文件"></a>1.4.配置文件</h2><p><strong><code>MySQL</code>配置文件讲解：<a target="_blank" rel="noopener" href="https://www.cnblogs.com/gaoyuechen/p/10273102.html">https://www.cnblogs.com/gaoyuechen/p/10273102.html</a></strong></p>
<p>1、二进制日志<code>log-bin</code>：主从复制。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> my.cnf</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 开启 mysql binlog 功能</span></span><br><span class="line">log-bin=mysql-bin</span><br></pre></td></tr></table></figure>

<p>2、错误日志<code>log-error</code>：默认是关闭的，记录严重的警告和错误信息，每次启动和关闭的详细信息等。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> my.cnf</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 数据库错误日志文件</span></span><br><span class="line">log-error = error.log</span><br></pre></td></tr></table></figure>

<p>3、查询日志<code>log</code>：默认关闭，记录查询的<code>sql</code>语句，如果开启会降低<code>MySQL</code>整体的性能，因为记录日志需要消耗系统资源。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> my.cnf</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 慢查询 sql 日志设置</span></span><br><span class="line">slow_query_log = 1</span><br><span class="line">slow_query_log_file = slow.log</span><br></pre></td></tr></table></figure>

<p>4、数据文件。</p>
<ul>
<li><code>frm文件</code>：存放表结构。</li>
<li><code>myd</code>文件：存放表数据。</li>
<li><code>myi</code>文件：存放表索引。</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> mysql5.7 使用 .frm 文件来存储表结构</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 使用 .ibd 文件来存储表索引和表数据</span></span><br><span class="line">-rw-r-----  1 mysql mysql   8988 Jun 25 09:31 pms_category.frm</span><br><span class="line">-rw-r-----  1 mysql mysql 245760 Jul 21 10:01 pms_category.ibd</span><br></pre></td></tr></table></figure>

<p><code>MySQL5.7</code>的<code>Innodb</code>存储引擎可将所有数据存放于<code>ibdata*</code>的共享表空间，也可将每张表存放于独立的<code>.ibd</code>文件的独立表空间。<br>共享表空间以及独立表空间都是针对数据的存储方式而言的。</p>
<ul>
<li>共享表空间: 某一个数据库的所有的表数据，索引文件全部放在一个文件中，默认这个共享表空间的文件路径在<code>data</code>目录下。 默认的文件名为<code>:ibdata1</code> 初始化为<code>10M</code>。</li>
<li>独立表空间: 每一个表都将会生成以独立的文件方式来进行存储，每一个表都有一个<code>.frm</code>表描述文件，还有一个<code>.ibd</code>文件。 其中这个文件包括了单独一个表的数据内容以及索引内容，默认情况下它的存储位置也是在表的位置之中。在配置文件<code>my.cnf</code>中设置： <code>innodb_file_per_table</code>。</li>
</ul>
<h1 id="2-MySQL-逻辑架构"><a href="#2-MySQL-逻辑架构" class="headerlink" title="2.MySQL 逻辑架构"></a>2.MySQL 逻辑架构</h1><p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdn.net/20180831173911997?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3pfcnlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70" alt="MySQL逻辑架构"></p>
<ul>
<li><p><code>Connectors</code>：指的是不同语言中与 SQL 的交互。</p>
</li>
<li><p><code>Connection Pool</code>：管理缓冲用户连接，线程处理等需要缓存的需求。<strong>MySQL 数据库的连接层。</strong></p>
</li>
<li><p><code> Management Serveices &amp; Utilities</code>：系统管理和控制工具。备份、安全、复制、集群等等。。</p>
</li>
<li><p><code>SQL Interface</code>：接受用户的 SQL 命令，并且返回用户需要查询的结果。</p>
</li>
<li><p><code>Parser</code>：SQL 语句解析器。</p>
</li>
<li><p><code>Optimizer</code>：查询优化器，SQL 语句在查询之前会使用查询优化器对查询进行优化。<strong>就是优化客户端请求query</strong>，根据客户端请求的 query 语句，和数据库中的一些统计信息，在一系列算法的基础上进行分析，得出一个最优的策略，告诉后面的程序如何取得这个 query 语句的结果。<strong>For Example</strong>： <code>select uid,name from user where gender = 1;</code>这个<code>select </code>查询先根据<code>where </code>语句进行选取，而不是先将表全部查询出来以后再进行<code>gender</code>过滤；然后根据<code>uid</code>和<code>name</code>进行属性投影，而不是将属性全部取出以后再进行过滤。最后将这两个查询条件联接起来生成最终查询结果。</p>
</li>
<li><p><code>Caches &amp; Buffers</code>：查询缓存。</p>
</li>
<li><p><code>Pluggable Storage Engines</code>：<strong>存储引擎接口。MySQL 区别于其他数据库的最重要的特点就是其插件式的表存储引擎(注意：存储引擎是基于表的，而不是数据库)。</strong></p>
</li>
<li><p><code>File System</code>：数据落地到磁盘上，就是文件的存储。</p>
</li>
</ul>
<p>MySQL 数据库和其他数据库相比，MySQL 有点与众不同，主要体现在存储引擎的架构上，<strong>插件式的存储引擎架构将查询处理和其他的系统任务以及数据的存储提取相分离</strong>。这种架构可以根据业务的需求和实际需求选择合适的存储引擎。</p>
<blockquote>
<p>逻辑架构分层</p>
</blockquote>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200801165252510.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JyaW5nb18=,size_16,color_FFFFFF,t_70" alt="MySQL逻辑架构"></p>
<ul>
<li><p>连接层：最上层是一些客户端和连接服务，包含本地 sock 通信和大多数基于客户端/服务端工具实现的类似于<code>tcp/ip</code>的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念，为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于<code>SSL</code>的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。</p>
</li>
<li><p>服务层：MySQL 的核心服务功能层，该层是 MySQL 的核心，包括查询缓存，解析器，解析树，预处理器，查询优化器。主要进行查询解析、分析、查询缓存、内置函数、存储过程、触发器、视图等，select 操作会先检查是否命中查询缓存，命中则直接返回缓存数据，否则解析查询并创建对应的解析树。</p>
</li>
<li><p>引擎层：存储引擎层，存储引擎真正的负责了 MySQL 中数据的存储和提取，服务器通过 API 与存储引擎进行通信。不同的存储引擎具有的功能不同，这样我们可以根据自己的实际需要进行选取。</p>
</li>
<li><p>存储层：数据存储层，主要是将数据存储在运行于裸设备的文件系统之上，并完成与存储引擎的交互。</p>
</li>
</ul>
<h1 id="3-存储引擎"><a href="#3-存储引擎" class="headerlink" title="3.存储引擎"></a>3.存储引擎</h1><p><code>show engines;</code>命令查看 MySQL5.7 支持的存储引擎。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> show engines;</span></span><br></pre></td></tr></table></figure>

<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200801170442428.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JyaW5nb18=,size_16,color_FFFFFF,t_70" alt="存储引擎"></p>
<p><code>show variables like &#39;default_storage_engine%&#39;;</code>查看当前数据库正在使用的存储引擎。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> show variables like <span class="string">&#x27;default_storage_engine%&#x27;</span>;</span></span><br><span class="line">+------------------------+--------+</span><br><span class="line">| Variable_name       | Value  |</span><br><span class="line">+------------------------+--------+</span><br><span class="line">| default_storage_engine | InnoDB |</span><br><span class="line">+------------------------+--------+</span><br><span class="line">1 row in set (0.01 sec)</span><br></pre></td></tr></table></figure>

<blockquote>
<p>InnoDB 和 MyISAM 对比</p>
</blockquote>
<table>
<thead>
<tr>
<th align="left">对比项</th>
<th align="center">MyISAM</th>
<th align="center">InnoDB</th>
</tr>
</thead>
<tbody><tr>
<td align="left">主外键</td>
<td align="center">不支持</td>
<td align="center">支持</td>
</tr>
<tr>
<td align="left">事务</td>
<td align="center">不支持</td>
<td align="center">支持</td>
</tr>
<tr>
<td align="left">行表锁</td>
<td align="center">表锁，即使操作一条记录也会锁住整张表，<br><strong>不适合高并发操作</strong></td>
<td align="center">行锁，操作时只锁某一行，不对其他行有影响，<br><strong>适合高并发操作</strong></td>
</tr>
<tr>
<td align="left">缓存</td>
<td align="center">只缓存索引，不缓存真实数据</td>
<td align="center">不仅缓存索引还要缓存真实数据，対内存要求较高，<br>而且内存大小対性能有决定性影响</td>
</tr>
<tr>
<td align="left">表空间</td>
<td align="center">小</td>
<td align="center">大</td>
</tr>
<tr>
<td align="left">关注点</td>
<td align="center">性能</td>
<td align="center">事务</td>
</tr>
<tr>
<td align="left">默认安装</td>
<td align="center">Y</td>
<td align="center">Y</td>
</tr>
</tbody></table>
<h1 id="4-SQL-性能下降的原因"><a href="#4-SQL-性能下降的原因" class="headerlink" title="4.SQL 性能下降的原因"></a>4.SQL 性能下降的原因</h1><ul>
<li>查询语句写的差。</li>
<li>索引失效：索引建了，但是没有用上。</li>
<li>关联 查询太多<code>join</code>（设计缺陷或者不得已的需求）。</li>
<li>服务器调优以及各个参数的设置（缓冲、线程数等）。</li>
</ul>
<h1 id="5-SQL-执行顺序"><a href="#5-SQL-执行顺序" class="headerlink" title="5.SQL 执行顺序"></a>5.SQL 执行顺序</h1><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">select              # 5</span><br><span class="line">	... </span><br><span class="line">from               # 1</span><br><span class="line">	... </span><br><span class="line">where              # 2</span><br><span class="line">	.... </span><br><span class="line">group by            # 3</span><br><span class="line">	... </span><br><span class="line">having             # 4</span><br><span class="line">	... </span><br><span class="line">order by            # 6</span><br><span class="line">	... </span><br><span class="line">limit               # 7</span><br><span class="line">	[offset]</span><br></pre></td></tr></table></figure>

<h1 id="6-七种-JOIN-理论"><a href="#6-七种-JOIN-理论" class="headerlink" title="6.七种 JOIN 理论"></a>6.七种 JOIN 理论</h1><p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200801212011559.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JyaW5nb18=,size_16,color_FFFFFF,t_70" alt="七种JOIN理论"></p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 1 */</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">&lt;</span>select_list<span class="operator">&gt;</span> <span class="keyword">FROM</span> TableA A <span class="keyword">LEFT</span> <span class="keyword">JOIN</span> TableB B <span class="keyword">ON</span> A.Key <span class="operator">=</span> B.Key;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 2 */</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">&lt;</span>select_list<span class="operator">&gt;</span> <span class="keyword">FROM</span> TableA A <span class="keyword">RIGHT</span> <span class="keyword">JOIN</span> TableB B <span class="keyword">ON</span> A.Key <span class="operator">=</span> B.Key;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 3 */</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">&lt;</span>select_list<span class="operator">&gt;</span> <span class="keyword">FROM</span> TableA A <span class="keyword">INNER</span> <span class="keyword">JOIN</span> TableB B <span class="keyword">ON</span> A.Key <span class="operator">=</span> B.Key;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 4 */</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">&lt;</span>select_list<span class="operator">&gt;</span> <span class="keyword">FROM</span> TableA A <span class="keyword">LEFT</span> <span class="keyword">JOIN</span> TableB B <span class="keyword">ON</span> A.Key <span class="operator">=</span> B.Key <span class="keyword">WHERE</span> B.Key <span class="keyword">IS</span> <span class="keyword">NULL</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 5 */</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">&lt;</span>select_list<span class="operator">&gt;</span> <span class="keyword">FROM</span> TableA A <span class="keyword">RIGHT</span> <span class="keyword">JOIN</span> TableB B <span class="keyword">ON</span> A.Key <span class="operator">=</span> B.Key <span class="keyword">WHERE</span> A.Key <span class="keyword">IS</span> <span class="keyword">NULL</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 6 */</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">&lt;</span>select_list<span class="operator">&gt;</span> <span class="keyword">FROM</span> TableA A <span class="keyword">FULL</span> <span class="keyword">OUTER</span> <span class="keyword">JOIN</span> TableB B <span class="keyword">ON</span> A.Key <span class="operator">=</span> B.Key;</span><br><span class="line"><span class="comment">/* MySQL不支持FULL OUTER JOIN这种语法 可以改成 1+2 */</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">&lt;</span>select_list<span class="operator">&gt;</span> <span class="keyword">FROM</span> TableA A <span class="keyword">LEFT</span> <span class="keyword">JOIN</span> TableB B <span class="keyword">ON</span> A.Key <span class="operator">=</span> B.Key</span><br><span class="line"><span class="keyword">UNION</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">&lt;</span>select_list<span class="operator">&gt;</span> <span class="keyword">FROM</span> TableA A <span class="keyword">RIGHT</span> <span class="keyword">JOIN</span> TableB B <span class="keyword">ON</span> A.Key <span class="operator">=</span> B.Key;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 7 */</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">&lt;</span>select_list<span class="operator">&gt;</span> <span class="keyword">FROM</span> TableA A <span class="keyword">FULL</span> <span class="keyword">OUTER</span> <span class="keyword">JOIN</span> TableB B <span class="keyword">ON</span> A.Key <span class="operator">=</span> B.Key <span class="keyword">WHERE</span> A.Key <span class="keyword">IS</span> <span class="keyword">NULL</span> <span class="keyword">OR</span> B.Key <span class="keyword">IS</span> <span class="keyword">NULL</span>;</span><br><span class="line"><span class="comment">/* MySQL不支持FULL OUTER JOIN这种语法 可以改成 4+5 */</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">&lt;</span>select_list<span class="operator">&gt;</span> <span class="keyword">FROM</span> TableA A <span class="keyword">LEFT</span> <span class="keyword">JOIN</span> TableB B <span class="keyword">ON</span> A.Key <span class="operator">=</span> B.Key <span class="keyword">WHERE</span> B.Key <span class="keyword">IS</span> <span class="keyword">NULL</span>;</span><br><span class="line"><span class="keyword">UNION</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">&lt;</span>select_list<span class="operator">&gt;</span> <span class="keyword">FROM</span> TableA A <span class="keyword">RIGHT</span> <span class="keyword">JOIN</span> TableB B <span class="keyword">ON</span> A.Key <span class="operator">=</span> B.Key <span class="keyword">WHERE</span> A.Key <span class="keyword">IS</span> <span class="keyword">NULL</span>;</span><br></pre></td></tr></table></figure>

<h1 id="7-索引"><a href="#7-索引" class="headerlink" title="7.索引"></a>7.索引</h1><h2 id="7-1-索引简介"><a href="#7-1-索引简介" class="headerlink" title="7.1.索引简介"></a>7.1.索引简介</h2><blockquote>
<p>索引是什么？</p>
</blockquote>
<p>MySQL 官方对索引的定义为：<strong>索引（INDEX）是帮助 MySQL 高效获取数据的数据结构。</strong></p>
<p>从而可以获得索引的本质：<strong>索引是排好序的快速查找数据结构。</strong></p>
<p>索引的目的在于提高查询效率，可以类比字典的目录。如果要查<code>mysql</code>这个这个单词，我们肯定要先定位到<code>m</code>字母，然后从上往下找<code>y</code>字母，再找剩下的<code>sql</code>。如果没有索引，那么可能需要<code>a---z</code>，这样全字典扫描，如果我想找<code>Java</code>开头的单词呢？如果我想找<code>Oracle</code>开头的单词呢？？？</p>
<p><strong>重点：索引会影响到 MySQL 查找 (WHERE的查询条件) 和排序 (ORDER BY) 两大功能！</strong></p>
<p><strong>除了数据本身之外，数据库还维护着一个满足特定查找算法的数据结构，这些数据结构以某种方式指向数据，这样就可以在这些数据结构的基础上实现高级查找算法，这种数据结构就是索引。</strong></p>
<p>一般来说，索引本身也很大，不可能全部存储在内存中，因此索引往往以索引文件的形式存储在磁盘上。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> Linux 下查看磁盘空间命令 df -h</span> </span><br><span class="line">[root@Ringo ~]# df -h</span><br><span class="line">Filesystem      Size   Used   Avail Use% Mounted on</span><br><span class="line">/dev/vda1        40G   16G    23G  41% /</span><br><span class="line">devtmpfs        911M    0   911M   0% /dev</span><br><span class="line">tmpfs          920M    0   920M   0% /dev/shm</span><br><span class="line">tmpfs          920M  480K    920M   1% /run</span><br><span class="line">tmpfs          920M    0   920M   0% /sys/fs/cgroup</span><br><span class="line">overlay         40G   16G    23G  41% </span><br></pre></td></tr></table></figure>

<p>我们平时所说的索引，如果没有特别指明，都是指 B树（多路搜索树，并不一定是二叉的）结构组织的索引。其中聚集索引、次要索引、覆盖索引、复合索引、前缀索引、唯一索引默认都是使用 B+ 树索引，统称索引。当然，除了 B+ 树这种数据结构的索引之外，还有哈希索引（Hash Index）等。</p>
<blockquote>
<p>索引的优势和劣势</p>
</blockquote>
<p>优势：</p>
<ul>
<li>查找：类似大学图书馆的书目索引，提高数据检索的效率，降低数据库的 IO 成本。</li>
<li>排序：通过索引対数据进行排序，降低数据排序的成本，降低了 CPU 的消耗。</li>
</ul>
<p>劣势：</p>
<ul>
<li>实际上索引也是一张表，该表保存了主键与索引字段，并指向实体表的记录，所以索引列也是要占用空间的。</li>
<li>虽然索引大大提高了查询速度，但是同时会降低表的更新速度，例如对表频繁的进行<code>INSERT</code>、<code>UPDATE</code>和<code>DELETE</code>。因为更新表的时候，MySQL 不仅要保存数据，还要保存一下索引文件每次更新添加的索引列的字段，都会调整因为更新所带来的键值变化后的索引信息。</li>
<li>索引只是提高效率的一个因素，如果 MySQL 有大数据量的表，就需要花时间研究建立最优秀的索引。</li>
</ul>
<h2 id="7-2-MySQL-索引分类"><a href="#7-2-MySQL-索引分类" class="headerlink" title="7.2.MySQL 索引分类"></a>7.2.MySQL 索引分类</h2><p>索引分类：</p>
<ul>
<li>单值索引：一个索引只包含单个列，一个表可以有多个单列索引。</li>
<li>唯一索引：索引列的值必须唯一，但是允许空值。</li>
<li>复合索引：一个索引包含多个字段。</li>
</ul>
<p><strong>建议：一张表建的索引最好不要超过 5 个！</strong></p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 基本语法 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 1、创建索引 [UNIQUE] 可以省略*/</span></span><br><span class="line"><span class="comment">/* 如果只写一个字段就是单值索引，写多个字段就是复合索引 */</span></span><br><span class="line"><span class="keyword">CREATE</span> [<span class="keyword">UNIQUE</span>] INDEX indexName <span class="keyword">ON</span> tabName(columnName(length));</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 2、删除索引 */</span></span><br><span class="line"><span class="keyword">DROP</span> INDEX [indexName] <span class="keyword">ON</span> tabName;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 3、查看索引 */</span></span><br><span class="line"><span class="comment">/* 加上\G就可以以列的形式查看了 不加\G就是以表的形式查看 */</span></span><br><span class="line"><span class="keyword">SHOW</span> INDEX <span class="keyword">FROM</span> tabName \G;</span><br></pre></td></tr></table></figure>

<h3 id="索引的命名规范"><a href="#索引的命名规范" class="headerlink" title="索引的命名规范"></a><strong>索引的命名规范</strong></h3><p>(1) 单张表中索引数量不超过 5 个。</p>
<p>(2) 单个索引中的字段数不超过 5 个。</p>
<p>(3) 索引名必须全部使用小写。</p>
<p>(4) 非唯一索引按照 “idx_字段名称 [字段名称]” 进用行命名。例如 idx_age_name。</p>
<p>(5) 唯一索引按照 “uniq_字段名称 [字段名称]” 进用行命名。例如 uniq_age_name。</p>
<p>(6) 组合索引建议包含所有字段名，过长的字段名可以采用缩写形式。例如 idx_age_name_add。</p>
<p>(7) 表必须有主键，<strong>推荐使用 UNSIGNED（无符号） 自增列作为主键</strong>。</p>
<p>(8) 唯一键由 3 个以下字段组成，并且字段都是整型时, 可使用唯一键作为主键。其他情况下，建议使用自增列或发号器作主键。</p>
<p>(9) 禁止冗余索引。</p>
<p>(10) 禁止重复索引。</p>
<p>(11) 禁止使用外键。</p>
<p>(12) 联表查询时，JOIN 列的数据类型必须相同，并且要建立索引。</p>
<p>(13) 不在低基数列（数据重复性高）上建立索引，例如 “性别”。</p>
<p>(14) 选择区分度大的列建立索引。组合索引中，区分度大的字段放在最前。</p>
<p>(15) 对字符串使用前缀索引，前缀索引长度不超过 8 个字符。</p>
<p>(16) 不对过长的 VARCHAR 字段建立索引。建议优先考虑前缀索引，或添加 CRC32 或 MD5 伪列并建立索引。</p>
<p>(17) 合理创建联合索引，(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c)。</p>
<p>(18) 合理使用覆盖索引减少 IO, 避免排序。</p>
<p>使用<code>ALTER</code>命令来为数据表添加索引</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 1、该语句添加一个主键，这意味着索引值必须是唯一的，并且不能为 NULL */</span></span><br><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> tabName <span class="keyword">ADD</span> <span class="keyword">PRIMARY</span> KEY(column_list);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 2、该语句创建索引的键值必须是唯一的(除了 NULL 之外，NULL 可能会出现多次) */</span></span><br><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> tabName <span class="keyword">ADD</span> <span class="keyword">UNIQUE</span> indexName(column_list);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 3、该语句创建普通索引，索引值可以出现多次 */</span></span><br><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> tabName <span class="keyword">ADD</span> INDEX indexName(column_list);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 4、该语句指定了索引为 FULLTEXT，用于全文检索 */</span></span><br><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> tabName <span class="keyword">ADD</span> FULLTEXT indexName(column_list);</span><br></pre></td></tr></table></figure>

<h2 id="7-3-MySQL-索引数据结构"><a href="#7-3-MySQL-索引数据结构" class="headerlink" title="7.3.MySQL 索引数据结构"></a>7.3.MySQL 索引数据结构</h2><p>索引数据结构：</p>
<ul>
<li><code>BTree</code>索引。</li>
<li><code>Hash</code>索引。</li>
<li><code>Full-text</code>全文索引。</li>
<li><code>R-Tree</code>索引。</li>
</ul>
<p><code>BTree</code>索引检索原理：</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200801233134931.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JyaW5nb18=,size_16,color_FFFFFF,t_70" alt="BTree"></p>
<h2 id="7-4-哪些情况需要建索引"><a href="#7-4-哪些情况需要建索引" class="headerlink" title="7.4.哪些情况需要建索引"></a>7.4.哪些情况需要建索引</h2><ul>
<li>主键自动建立主键索引（唯一 + 非空）。</li>
<li>频繁作为查询条件的字段应该创建索引。</li>
<li>查询中与其他表关联的字段，外键关系建立索引。</li>
<li>查询中排序的字段，<strong>排序字段若通过索引去访问将大大提高排序速度</strong>。</li>
<li>查询中统计或者分组字段（group by 也和索引有关）。</li>
</ul>
<h2 id="7-5-那些情况不要建索引"><a href="#7-5-那些情况不要建索引" class="headerlink" title="7.5.那些情况不要建索引"></a>7.5.那些情况不要建索引</h2><ul>
<li><p>记录太少的表。[10W-100W条数据可创建索引，千万级创建索引耗时较久，创建时长会大于10min]</p>
</li>
<li><p>经常增删改的表。</p>
</li>
<li><p>频繁更新的字段不适合创建索引。</p>
</li>
<li><p>Where 条件里用不到的字段不创建索引。</p>
</li>
<li><p>假如一个表有 10 万行记录，有一个字段 A 只有 true 和 false 两种值，并且每个值的分布概率大约为 50%，那么对 A 字段建索引一般不会提高数据库的查询速度。索引的选择性是指索引列中不同值的数目与表中记录数的比。如果一个表中有 2000 条记录，表索引列有 1980 个不同的值，那么这个索引的选择性就是1980/2000=0.99。一个索引的选择性越接近于 1，这个索引的效率就越高。</p>
</li>
</ul>
<h4 id="7-6-开启和关闭索引"><a href="#7-6-开启和关闭索引" class="headerlink" title="7.6 开启和关闭索引"></a>7.6 开启和关闭索引</h4><p>关闭：ALTER TABLE <code>test</code> DISABLE KEYS ;<br>开启：ALTER TABLE <code>test</code> ENABLE KEYS;</p>
<h1 id="8-性能分析"><a href="#8-性能分析" class="headerlink" title="8.性能分析"></a>8.性能分析</h1><h2 id="8-1-EXPLAIN-简介"><a href="#8-1-EXPLAIN-简介" class="headerlink" title="8.1.EXPLAIN 简介"></a>8.1.EXPLAIN 简介</h2><blockquote>
<p>EXPLAIN是什么？</p>
</blockquote>
<p>EXPLAIN：SQL 的执行计划，使用 EXPLAIN 关键字可以模拟优化器执行 SQL 查询语句，从而知道 MySQL 是如何处理 SQL 语句的。</p>
<blockquote>
<p>EXPLAIN 怎么使用？</p>
</blockquote>
<p>语法：<code>explain</code> + <code>SQL</code>。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> explain select * from pms_category \G;</span></span><br><span class="line">*************************** 1. row ***************************</span><br><span class="line">           id: 1</span><br><span class="line">  select_type: SIMPLE</span><br><span class="line">        table: pms_category</span><br><span class="line">   partitions: NULL</span><br><span class="line">         type: ALL</span><br><span class="line">possible_keys: NULL</span><br><span class="line">          key: NULL</span><br><span class="line">      key_len: NULL</span><br><span class="line">          ref: NULL</span><br><span class="line">         rows: 1425</span><br><span class="line">     filtered: 100.00</span><br><span class="line">        Extra: NULL</span><br><span class="line">1 row in set, 1 warning (0.00 sec)</span><br></pre></td></tr></table></figure>

<blockquote>
<p>EXPLAIN 能干嘛？</p>
</blockquote>
<p>可以查看以下信息：</p>
<ul>
<li><code>id</code>：表的读取顺序。</li>
<li><code>select_type</code>：数据读取操作的操作类型。</li>
<li><code>possible_keys</code>：哪些索引可以使用。</li>
<li><code>key</code>：哪些索引被实际使用。</li>
<li><code>ref</code>：表之间的引用。</li>
<li><code>rows</code>：每张表有多少行被优化器查询。</li>
</ul>
<h2 id="8-2-EXPLAIN-字段"><a href="#8-2-EXPLAIN-字段" class="headerlink" title="8.2.EXPLAIN 字段"></a>8.2.EXPLAIN 字段</h2><blockquote>
<p>id</p>
</blockquote>
<p><code>id</code>：表的读取和加载顺序。</p>
<p>值有以下三种情况：</p>
<ul>
<li><code>id</code>相同，执行顺序由上至下。</li>
<li><code>id</code>不同，如果是子查询，id 的序号会递增，<strong>id 值越大优先级越高，越先被执行。</strong></li>
<li><code>id</code>相同不同，同时存在。<strong>永远是 id 大的优先级最高，id 相等的时候顺序执行。</strong></li>
</ul>
<blockquote>
<p>select_type</p>
</blockquote>
<p><code>select_type</code>：数据查询的类型，主要是用于区别，普通查询、联合查询、子查询等的复杂查询。</p>
<ul>
<li><code>SIMPLE</code>：简单的<code>SELECT</code>查询，查询中不包含子查询或者<code>UNION </code>。</li>
<li><code>PRIMARY</code>：查询中如果包含任何复杂的子部分，最外层查询则被标记为<code>PRIMARY</code>。</li>
<li><code>SUBQUERY</code>：在<code>SELECT</code>或者<code>WHERE</code>子句中包含了子查询。</li>
<li><code>DERIVED</code>：在<code>FROM</code>子句中包含的子查询被标记为<code>DERIVED(衍生)</code>，MySQL 会递归执行这些子查询，把结果放在临时表中。</li>
<li><code>UNION</code>：如果第二个<code>SELECT</code>出现在<code>UNION</code>之后，则被标记为<code>UNION</code>；若<code>UNION</code>包含在<code>FROM</code>子句的子查询中，外层<code>SELECT</code>将被标记为<code>DERIVED</code>。</li>
<li><code>UNION RESULT</code>：从<code>UNION</code>表获取结果的<code>SELECT</code>。</li>
</ul>
<blockquote>
<p>type</p>
</blockquote>
<p><code>type</code>：访问类型排列。</p>
<p><strong>从最好到最差依次是：</strong><code>system</code>&gt;<code>const</code>&gt;<code>eq_ref</code>&gt;<code>ref</code>&gt;<code>range</code>&gt;<code>index</code>&gt;<code>ALL</code>。除了<code>ALL</code>没有用到索引，其他级别都用到索引了。</p>
<p>一般来说，得保证查询至少达到<code>range</code>级别，最好达到<code>ref</code>。</p>
<ul>
<li><p><code>system</code>：表只有一行记录（等于系统表），这是<code>const</code>类型的特例，平时不会出现，这个也可以忽略不计。</p>
</li>
<li><p><code>const</code>：表示通过索引一次就找到了，<code>const</code>用于比较<code>primary key</code>或者<code>unique</code>索引。因为只匹配一行数据，所以很快。如将主键置于<code>where</code>列表中，MySQL就能将该查询转化为一个常量。</p>
</li>
<li><p><code>eq_ref</code>：唯一性索引扫描，读取本表中和关联表表中的每行组合成的一行，查出来只有一条记录。除 了 <code>system</code> 和<code> const</code> 类型之外, 这是最好的联接类型。</p>
</li>
<li><p><code>ref</code>：非唯一性索引扫描，返回本表和关联表某个值匹配的所有行，查出来有多条记录。</p>
</li>
<li><p><code>range</code>：只检索给定范围的行，一般就是在<code>WHERE</code>语句中出现了<code>BETWEEN</code>、<code>&lt; &gt;</code>、<code>in</code>等的查询。这种范围扫描索引比全表扫描要好，因为它只需要开始于索引树的某一点，而结束于另一点，不用扫描全部索引。</p>
</li>
<li><p><code>index</code>：<code>Full Index Scan</code>，全索引扫描，<code>index</code>和<code>ALL</code>的区别为<code>index</code>类型只遍历索引树。<strong>也就是说虽然<code>ALL</code>和<code>index</code>都是读全表，但是<code>index</code>是从索引中读的，<code>ALL</code>是从磁盘中读取的。</strong></p>
</li>
<li><p><code>ALL</code>：<code>Full Table Scan</code>，没有用到索引，全表扫描。</p>
</li>
</ul>
<blockquote>
<p>possible_keys 和 key</p>
</blockquote>
<p><code>possible_keys</code>：显示可能应用在这张表中的索引，一个或者多个。查询涉及到的字段上若存在索引，则该索引将被列出，<strong>但不一定被查询实际使用。</strong></p>
<p><code>key</code>：实际使用的索引。如果为<code>NULL</code>，则没有使用索引。查询中如果使用了覆盖索引，则该索引仅仅出现在<code>key</code>列表中。</p>
<blockquote>
<p>key_len</p>
</blockquote>
<p><code>key_len</code>：表示索引中使用的字节数，可通过该列计算查询中使用的索引的长度。<code>key_len</code>显示的值为索引字段的最大可能长度，并非实际使用长度，即<code>key_len</code>是根据表定义计算而得，不是通过表内检索出的。在不损失精度的情况下，长度越短越好。</p>
<p><code>key_len</code>计算规则：<strong><a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_34930488/article/details/102931490">https://blog.csdn.net/qq_34930488/article/details/102931490</a></strong></p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> desc pms_category;</span></span><br><span class="line">+---------------+------------+------+-----+---------+----------------+</span><br><span class="line">| Field      | Type       | Null | Key | Default | Extra        |</span><br><span class="line">+---------------+------------+------+-----+---------+----------------+</span><br><span class="line">| cat_id      | bigint(20)  | NO   | PRI  | NULL    | auto_increment |</span><br><span class="line">| name       | char(50)   | YES  |     | NULL    |           |</span><br><span class="line">| parent_cid   | bigint(20)  | YES  |     | NULL    |           |</span><br><span class="line">| cat_level    | int(11)    | YES  |     | NULL    |           |</span><br><span class="line">| show_status  | tinyint(4)   | YES  |     | NULL    |           |</span><br><span class="line">| sort       | int(11)    | YES  |     | NULL    |           |</span><br><span class="line">| icon       | char(255)   | YES  |     | NULL    |           |</span><br><span class="line">| product_unit  | char(50)   | YES  |     | NULL    |           |</span><br><span class="line">| product_count | int(11)    | YES  |     | NULL    |           |</span><br><span class="line">+---------------+------------+------+-----+---------+----------------+</span><br><span class="line">9 rows in set (0.00 sec)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> explain select cat_id from pms_category <span class="built_in">where</span> cat_id between 10 and 20 \G;</span></span><br><span class="line">*************************** 1. row ***************************</span><br><span class="line">           id: 1</span><br><span class="line">  select_type: SIMPLE</span><br><span class="line">        table: pms_category</span><br><span class="line">   partitions: NULL</span><br><span class="line">         type: range</span><br><span class="line">possible_keys: PRIMARY</span><br><span class="line">          key: PRIMARY  # 用到了主键索引，通过查看表结构知道，cat_id 是 bigint 类型，占用 8 个字节</span><br><span class="line">      key_len: 8        # 这里只用到了 cat_id 主键索引，所以长度就是8！</span><br><span class="line">          ref: NULL</span><br><span class="line">         rows: 11</span><br><span class="line">     filtered: 100.00</span><br><span class="line">        Extra: Using where; Using index</span><br><span class="line">1 row in set, 1 warning (0.00 sec)</span><br></pre></td></tr></table></figure>



<blockquote>
<p>ref</p>
</blockquote>
<p><code>ref</code>：显示索引的哪一列被使用了，如果可能的话，是一个常数。哪些列或常量被用于查找索引列上的值。</p>
<blockquote>
<p>rows</p>
</blockquote>
<p><code>rows</code>：根据表统计信息及索引选用情况，大致估算出找到所需的记录需要读取的行数。</p>
<blockquote>
<p>Extra</p>
</blockquote>
<p><code>Extra</code>：包含不适合在其他列中显示但十分重要的额外信息。</p>
<ul>
<li><code>Using filesort</code>：说明 MySQL 会对数据使用一个外部的索引排序，而不是按照表内的索引顺序进行读取。<strong>MySQL中无法利用索引完成的排序操作成为”文件内排序”。</strong></li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 排序没有使用索引</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> explain select name from pms_category <span class="built_in">where</span> name=<span class="string">&#x27;Tangs&#x27;</span> order by cat_level \G</span></span><br><span class="line">*************************** 1. row ***************************</span><br><span class="line">           id: 1</span><br><span class="line">  select_type: SIMPLE</span><br><span class="line">        table: pms_category</span><br><span class="line">   partitions: NULL</span><br><span class="line">         type: ref</span><br><span class="line">possible_keys: idx_name_parentCid_catLevel</span><br><span class="line">          key: idx_name_parentCid_catLevel</span><br><span class="line">      key_len: 201</span><br><span class="line">          ref: const</span><br><span class="line">         rows: 1</span><br><span class="line">     filtered: 100.00</span><br><span class="line">        Extra: Using where; Using index; Using filesort</span><br><span class="line">1 row in set, 1 warning (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 排序使用到了索引</span></span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> explain select name from pms_category <span class="built_in">where</span> name=<span class="string">&#x27;Tangs&#x27;</span> order by parent_cid,cat_level\G</span></span><br><span class="line">*************************** 1. row ***************************</span><br><span class="line">           id: 1</span><br><span class="line">  select_type: SIMPLE</span><br><span class="line">        table: pms_category</span><br><span class="line">   partitions: NULL</span><br><span class="line">         type: ref</span><br><span class="line">possible_keys: idx_name_parentCid_catLevel</span><br><span class="line">          key: idx_name_parentCid_catLevel</span><br><span class="line">      key_len: 201</span><br><span class="line">          ref: const</span><br><span class="line">         rows: 1</span><br><span class="line">     filtered: 100.00</span><br><span class="line">        Extra: Using where; Using index</span><br><span class="line">1 row in set, 1 warning (0.00 sec)</span><br></pre></td></tr></table></figure>

<ul>
<li><p><code>Using temporary</code>：使用了临时表保存中间结果，MySQL 在対查询结果排序时使用了临时表。常见于排序<code>order by</code>和分组查询<code>group by</code>。<strong>临时表対系统性能损耗很大。</strong></p>
</li>
<li><p><code>Using index</code>：表示相应的<code>SELECT</code>操作中使用了覆盖索引，避免访问了表的数据行，效率不错！如果同时出现<code>Using where</code>，表示索引被用来执行索引键值的查找；如果没有同时出现<code>Using where</code>，表明索引用来读取数据而非执行查找动作。</p>
</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 覆盖索引</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 就是 select 的数据列只用从索引中就能够取得，不必从数据表中读取，换句话说查询列要被所使用的索引覆盖。</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 注意：如果要使用覆盖索引，一定不能写 SELECT *，要写出具体的字段。</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> explain select cat_id from pms_category \G;</span></span><br><span class="line">*************************** 1. row ***************************</span><br><span class="line">           id: 1</span><br><span class="line">  select_type: SIMPLE</span><br><span class="line">        table: pms_category</span><br><span class="line">   partitions: NULL</span><br><span class="line">         type: index</span><br><span class="line">possible_keys: NULL       </span><br><span class="line">          key: PRIMARY</span><br><span class="line">      key_len: 8</span><br><span class="line">          ref: NULL</span><br><span class="line">         rows: 1425</span><br><span class="line">     filtered: 100.00</span><br><span class="line">        Extra: Using index   # select 的数据列只用从索引中就能够取得，不必从数据表中读取   </span><br><span class="line">1 row in set, 1 warning (0.00 sec)</span><br></pre></td></tr></table></figure>

<ul>
<li><code>Using where</code>：表明使用了<code>WHERE</code>过滤。</li>
<li><code>Using join buffer</code>：使用了连接缓存。</li>
<li><code>impossible where</code>：<code>WHERE</code>子句的值总是 false，不能用来获取任何元组。</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> explain select name from pms_category <span class="built_in">where</span> name = <span class="string">&#x27;zs&#x27;</span> and name = <span class="string">&#x27;ls&#x27;</span>\G</span></span><br><span class="line">*************************** 1. row ***************************</span><br><span class="line">           id: 1</span><br><span class="line">  select_type: SIMPLE</span><br><span class="line">        table: NULL</span><br><span class="line">   partitions: NULL</span><br><span class="line">         type: NULL</span><br><span class="line">possible_keys: NULL</span><br><span class="line">          key: NULL</span><br><span class="line">      key_len: NULL</span><br><span class="line">          ref: NULL</span><br><span class="line">         rows: NULL</span><br><span class="line">     filtered: NULL</span><br><span class="line">        Extra: Impossible WHERE   # 不可能字段同时查到两个名字</span><br><span class="line">1 row in set, 1 warning (0.00 sec)</span><br></pre></td></tr></table></figure>

<h1 id="9-索引分析"><a href="#9-索引分析" class="headerlink" title="9.索引分析"></a>9.索引分析</h1><h2 id="9-1-单表索引分析"><a href="#9-1-单表索引分析" class="headerlink" title="9.1.单表索引分析"></a>9.1.单表索引分析</h2><blockquote>
<p>数据准备</p>
</blockquote>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">DROP</span> <span class="keyword">TABLE</span> IF <span class="keyword">EXISTS</span> `article`;</span><br><span class="line"></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> IF <span class="keyword">NOT</span> <span class="keyword">EXISTS</span> `article`(</span><br><span class="line">`id` <span class="type">INT</span>(<span class="number">10</span>) UNSIGNED <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">PRIMARY</span> KEY AUTO_INCREMENT COMMENT <span class="string">&#x27;主键&#x27;</span>,</span><br><span class="line">`author_id` <span class="type">INT</span>(<span class="number">10</span>) UNSIGNED <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;作者id&#x27;</span>,</span><br><span class="line">`category_id` <span class="type">INT</span>(<span class="number">10</span>) UNSIGNED <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;分类id&#x27;</span>,</span><br><span class="line">`views` <span class="type">INT</span>(<span class="number">10</span>) UNSIGNED <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;被查看的次数&#x27;</span>,</span><br><span class="line">`comments` <span class="type">INT</span>(<span class="number">10</span>) UNSIGNED <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;回帖的备注&#x27;</span>,</span><br><span class="line">`title` <span class="type">VARCHAR</span>(<span class="number">255</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;标题&#x27;</span>,</span><br><span class="line">`content` <span class="type">VARCHAR</span>(<span class="number">255</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;正文内容&#x27;</span></span><br><span class="line">) COMMENT <span class="string">&#x27;文章&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `article`(`author_id`, `category_id`, `views`, `comments`, `title`, `content`) <span class="keyword">VALUES</span>(<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="string">&#x27;1&#x27;</span>,<span class="string">&#x27;1&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `article`(`author_id`, `category_id`, `views`, `comments`, `title`, `content`) <span class="keyword">VALUES</span>(<span class="number">2</span>,<span class="number">2</span>,<span class="number">2</span>,<span class="number">2</span>,<span class="string">&#x27;2&#x27;</span>,<span class="string">&#x27;2&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `article`(`author_id`, `category_id`, `views`, `comments`, `title`, `content`) <span class="keyword">VALUES</span>(<span class="number">3</span>,<span class="number">3</span>,<span class="number">3</span>,<span class="number">3</span>,<span class="string">&#x27;3&#x27;</span>,<span class="string">&#x27;3&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `article`(`author_id`, `category_id`, `views`, `comments`, `title`, `content`) <span class="keyword">VALUES</span>(<span class="number">1</span>,<span class="number">1</span>,<span class="number">3</span>,<span class="number">3</span>,<span class="string">&#x27;3&#x27;</span>,<span class="string">&#x27;3&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `article`(`author_id`, `category_id`, `views`, `comments`, `title`, `content`) <span class="keyword">VALUES</span>(<span class="number">1</span>,<span class="number">1</span>,<span class="number">4</span>,<span class="number">4</span>,<span class="string">&#x27;4&#x27;</span>,<span class="string">&#x27;4&#x27;</span>);</span><br></pre></td></tr></table></figure>



<blockquote>
<p>案例：查询<code>category_id</code>为 1 且<code>comments</code>大于 1 的情况下，<code>views</code>最多的<code>article_id</code>。</p>
</blockquote>
<p>1、编写 SQL 语句并查看 SQL 执行计划。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1、sql语句</span></span><br><span class="line">SELECT id,author_id FROM article WHERE category_id = 1 AND comments &gt; 1 ORDER BY views DESC LIMIT 1;</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 2、sql执行计划</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 AND comments &gt; 1 ORDER BY views DESC LIMIT 1\G</span></span><br><span class="line">*************************** 1. row ***************************</span><br><span class="line">           id: 1</span><br><span class="line">  select_type: SIMPLE</span><br><span class="line">        table: article</span><br><span class="line">   partitions: NULL</span><br><span class="line">         type: ALL</span><br><span class="line">possible_keys: NULL</span><br><span class="line">          key: NULL</span><br><span class="line">      key_len: NULL</span><br><span class="line">          ref: NULL</span><br><span class="line">         rows: 5</span><br><span class="line">     filtered: 20.00</span><br><span class="line">        Extra: Using where; Using filesort  # 产生了文件内排序，需要优化 SQL</span><br><span class="line">1 row in set, 1 warning (0.00 sec)</span><br></pre></td></tr></table></figure>



<p>2、创建索引<code>idx_article_ccv</code>。</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> INDEX idx_article_ccv <span class="keyword">ON</span> article(category_id,comments,views);</span><br></pre></td></tr></table></figure>

<p>3、查看当前索引。</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803134154162.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JyaW5nb18=,size_16,color_FFFFFF,t_70" alt="show index"></p>
<p>4、查看现在SQL语句的执行计划。</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803134549914.png" alt="explain"></p>
<p>我们发现，创建符合索引<code>idx_article_ccv</code>之后，虽然解决了全表扫描的问题，但是在<code>order by</code>排序的时候没有用到索引，MySQL 居然还是用的<code>Using filesort</code>，为什么？</p>
<p>5、我们试试把 SQL 修改为<code>SELECT id,author_id FROM article WHERE category_id = 1 AND comments = 1 ORDER BY views DESC LIMIT 1;</code>看看 SQL 的执行计划。</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803135228945.png" alt="explain"></p>
<p>推论：当<code>comments &gt; 1</code>的时候<code>order by</code>排序<code>views</code>字段索引就用不上，但是当<code>comments = 1</code>的时候<code>order by</code>排序<code>views</code>字段索引就可以用上！！！<strong>所以，范围之后的索引会失效。</strong></p>
<p>6、我们现在知道<strong>范围之后的索引会失效</strong>，原来的索引<code>idx_article_ccv</code>最后一个字段<code>views</code>会失效，那么我们如果删除这个索引，创建<code>idx_article_cv</code>索引呢？？？？</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 创建索引 idx_article_cv */</span></span><br><span class="line"><span class="keyword">CREATE</span> INDEX idx_article_cv <span class="keyword">ON</span> article(category_id,views);</span><br></pre></td></tr></table></figure>

<p>查看当前的索引</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803140542912.png" alt="show index"></p>
<p>7、当前索引是<code>idx_article_cv</code>，来看一下 SQL 执行计划。</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803140951803.png" alt="explain"></p>
<h2 id="9-2-两表索引分析"><a href="#9-2-两表索引分析" class="headerlink" title="9.2.两表索引分析"></a>9.2.两表索引分析</h2><blockquote>
<p>数据准备</p>
</blockquote>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">DROP</span> <span class="keyword">TABLE</span> IF <span class="keyword">EXISTS</span> `class`;</span><br><span class="line"><span class="keyword">DROP</span> <span class="keyword">TABLE</span> IF <span class="keyword">EXISTS</span> `book`;</span><br><span class="line"></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> IF <span class="keyword">NOT</span> <span class="keyword">EXISTS</span> `class`(</span><br><span class="line">`id` <span class="type">INT</span>(<span class="number">10</span>) UNSIGNED <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">PRIMARY</span> KEY AUTO_INCREMENT COMMENT <span class="string">&#x27;主键&#x27;</span>,</span><br><span class="line">`card` <span class="type">INT</span>(<span class="number">10</span>) UNSIGNED <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;分类&#x27;</span> </span><br><span class="line">) COMMENT <span class="string">&#x27;商品类别&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> IF <span class="keyword">NOT</span> <span class="keyword">EXISTS</span> `book`(</span><br><span class="line">`bookid` <span class="type">INT</span>(<span class="number">10</span>) UNSIGNED <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">PRIMARY</span> KEY AUTO_INCREMENT COMMENT <span class="string">&#x27;主键&#x27;</span>,</span><br><span class="line">`card` <span class="type">INT</span>(<span class="number">10</span>) UNSIGNED <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;分类&#x27;</span></span><br><span class="line">) COMMENT <span class="string">&#x27;书籍&#x27;</span>;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>两表连接查询的 SQL 执行计划</p>
</blockquote>
<p>1、不创建索引的情况下，SQL 的执行计划。</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803143557187.png" alt="explain"></p>
<p><code>book</code>和<code>class</code>两张表都是没有使用索引，全表扫描，那么如果进行优化，索引是创建在<code>book</code>表还是创建在<code>class</code>表呢？下面进行大胆的尝试！</p>
<p>2、左表(<code>book</code>表)创建索引。</p>
<p>创建索引<code>idx_book_card</code></p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 在book表创建索引 */</span></span><br><span class="line"><span class="keyword">CREATE</span> INDEX idx_book_card <span class="keyword">ON</span> book(card);</span><br></pre></td></tr></table></figure>

<p>在<code>book</code>表中有<code>idx_book_card</code>索引的情况下，查看 SQL 执行计划</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803144429349.png" alt="explain"></p>
<p>3、删除<code>book</code>表的索引，右表(<code>class</code>表)创建索引。</p>
<p>创建索引<code>idx_class_card</code></p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 在class表创建索引 */</span></span><br><span class="line"><span class="keyword">CREATE</span> INDEX idx_class_card <span class="keyword">ON</span> class(card);</span><br></pre></td></tr></table></figure>

<p>在<code>class</code>表中有<code>idx_class_card</code>索引的情况下，查看 SQL 执行计划</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803145030597.png" alt="explain"></p>
<p><strong>由此可见，左连接将索引创建在右表上更合适，右连接将索引创建在左表上更合适。</strong></p>
<h2 id="9-3-三张表索引分析"><a href="#9-3-三张表索引分析" class="headerlink" title="9.3.三张表索引分析"></a>9.3.三张表索引分析</h2><blockquote>
<p>数据准备</p>
</blockquote>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">DROP</span> <span class="keyword">TABLE</span> IF <span class="keyword">EXISTS</span> `phone`;</span><br><span class="line"></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> IF <span class="keyword">NOT</span> <span class="keyword">EXISTS</span> `phone`(</span><br><span class="line">`phone_id` <span class="type">INT</span>(<span class="number">10</span>) UNSIGNED <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">PRIMARY</span> KEY AUTO_INCREMENT COMMENT <span class="string">&#x27;主键&#x27;</span>,</span><br><span class="line">`card` <span class="type">INT</span>(<span class="number">10</span>) UNSIGNED <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;分类&#x27;</span> </span><br><span class="line">) COMMENT <span class="string">&#x27;手机&#x27;</span>;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>三表连接查询SQL优化</p>
</blockquote>
<p>1、不加任何索引，查看SQL执行计划。</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803160631786.png" alt="explain"></p>
<p>2、根据两表查询优化的经验，左连接需要在右表上添加索引，所以尝试在<code>book</code>表和<code>phone</code>表上添加索引。</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 在book表创建索引 */</span></span><br><span class="line"><span class="keyword">CREATE</span> INDEX idx_book_card <span class="keyword">ON</span> book(card);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 在phone表上创建索引 */</span></span><br><span class="line"><span class="keyword">CREATE</span> INDEX idx_phone_card <span class="keyword">ON</span> phone(card);</span><br></pre></td></tr></table></figure>

<p>再次执行SQL的执行计划</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803161013880.png" alt="explain"></p>
<h2 id="9-4-结论"><a href="#9-4-结论" class="headerlink" title="9.4.结论"></a>9.4.结论</h2><p><code>JOIN</code>语句的优化：</p>
<ul>
<li>尽可能减少<code>JOIN</code>语句中的<code>NestedLoop</code>（嵌套循环）的总次数：<strong>永远都是小的结果集驱动大的结果集</strong>。</li>
<li>优先优化<code>NestedLoop</code>的内层循环。</li>
<li>保证<code>JOIN</code>语句中被驱动表上<code>JOIN</code>条件字段已经被索引。</li>
<li>当无法保证被驱动表的<code>JOIN</code>条件字段被索引且内存资源充足的前提下，不要太吝惜<code>Join Buffer</code> 的设置。</li>
</ul>
<h1 id="10-索引失效"><a href="#10-索引失效" class="headerlink" title="10.索引失效"></a>10.索引失效</h1><blockquote>
<p>数据准备</p>
</blockquote>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> `staffs`(</span><br><span class="line">`id` <span class="type">INT</span>(<span class="number">10</span>) <span class="keyword">PRIMARY</span> KEY AUTO_INCREMENT,</span><br><span class="line">`name` <span class="type">VARCHAR</span>(<span class="number">24</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="string">&#x27;&#x27;</span> COMMENT <span class="string">&#x27;姓名&#x27;</span>,</span><br><span class="line">`age` <span class="type">INT</span>(<span class="number">10</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="number">0</span> COMMENT <span class="string">&#x27;年龄&#x27;</span>,</span><br><span class="line">`pos` <span class="type">VARCHAR</span>(<span class="number">20</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="string">&#x27;&#x27;</span> COMMENT <span class="string">&#x27;职位&#x27;</span>,</span><br><span class="line">`add_time` <span class="type">TIMESTAMP</span> <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="string">&#x27;入职时间&#x27;</span></span><br><span class="line">)COMMENT <span class="string">&#x27;员工记录表&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `staffs`(`name`,`age`,`pos`) <span class="keyword">VALUES</span>(<span class="string">&#x27;Ringo&#x27;</span>, <span class="number">18</span>, <span class="string">&#x27;manager&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `staffs`(`name`,`age`,`pos`) <span class="keyword">VALUES</span>(<span class="string">&#x27;张三&#x27;</span>, <span class="number">20</span>, <span class="string">&#x27;dev&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `staffs`(`name`,`age`,`pos`) <span class="keyword">VALUES</span>(<span class="string">&#x27;李四&#x27;</span>, <span class="number">21</span>, <span class="string">&#x27;dev&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建索引 */</span></span><br><span class="line"><span class="keyword">CREATE</span> INDEX idx_staffs_name_age_pos <span class="keyword">ON</span> `staffs`(`name`,`age`,`pos`);</span><br></pre></td></tr></table></figure>

<h2 id="10-1-索引失效的情况"><a href="#10-1-索引失效的情况" class="headerlink" title="10.1.索引失效的情况"></a>10.1.索引失效的情况</h2><ol>
<li>全值匹配我最爱。</li>
<li>最佳左前缀法则。</li>
<li>不在索引列上做任何操作（计算、函数、(自动 or 手动)类型转换），会导致索引失效而转向全表扫描。</li>
<li>索引中范围条件右边的字段会全部失效。</li>
<li>尽量使用覆盖索引（只访问索引的查询，索引列和查询列一致），减少<code>SELECT *</code>。</li>
<li>MySQL 在使用<code>!=</code>或者<code>&lt;&gt;</code>的时候无法使用索引会导致全表扫描。</li>
<li><code>is null</code>、<code>is not null</code>也无法使用索引。</li>
<li><code>like</code>以通配符开头<code>%abc</code>索引失效会变成全表扫描。</li>
<li>字符串不加单引号索引失效。</li>
<li>少用<code>or</code>，用它来连接时会索引失效。</li>
</ol>
<h2 id="10-2-最佳左前缀法则"><a href="#10-2-最佳左前缀法则" class="headerlink" title="10.2.最佳左前缀法则"></a>10.2.最佳左前缀法则</h2><blockquote>
<p>案例</p>
</blockquote>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 用到了 idx_staffs_name_age_pos 索引中的 name 字段 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="operator">=</span> <span class="string">&#x27;Ringo&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 用到了 idx_staffs_name_age_pos 索引中的 name, age 字段 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="operator">=</span> <span class="string">&#x27;Ringo&#x27;</span> <span class="keyword">AND</span> `age` <span class="operator">=</span> <span class="number">18</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 用到了 idx_staffs_name_age_pos 索引中的name，age，pos 字段 这是属于全值匹配的情况！！！*/</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="operator">=</span> <span class="string">&#x27;Ringo&#x27;</span> <span class="keyword">AND</span> `age` <span class="operator">=</span> <span class="number">18</span> <span class="keyword">AND</span> `pos` <span class="operator">=</span> <span class="string">&#x27;manager&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 索引没用上，ALL 全表扫描 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `age` <span class="operator">=</span> <span class="number">18</span> <span class="keyword">AND</span> `pos` <span class="operator">=</span> <span class="string">&#x27;manager&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 索引没用上，ALL 全表扫描 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `pos` <span class="operator">=</span> <span class="string">&#x27;manager&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 用到了 idx_staffs_name_age_pos 索引中的 name 字段，pos 字段索引失效 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="operator">=</span> <span class="string">&#x27;Ringo&#x27;</span> <span class="keyword">AND</span> `pos` <span class="operator">=</span> <span class="string">&#x27;manager&#x27;</span>;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>概念</p>
</blockquote>
<p><strong>最佳左前缀法则：如果索引是多字段的复合索引，要遵守最佳左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的字段。</strong></p>
<p><strong>口诀：带头大哥不能死，中间兄弟不能断。</strong></p>
<h2 id="10-3-索引列上不计算"><a href="#10-3-索引列上不计算" class="headerlink" title="10.3.索引列上不计算"></a>10.3.索引列上不计算</h2><blockquote>
<p>案例</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 现在要查询 `name` = <span class="string">&#x27;Ringo&#x27;</span> 的记录下面有两种方式来查询！</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 1、直接使用 字段 = 值的方式来计算</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SELECT * FROM `staffs` WHERE `name` = <span class="string">&#x27;Ringo&#x27;</span>;</span></span><br><span class="line">+----+-------+-----+---------+---------------------+</span><br><span class="line">| id | name  | age | pos     | add_time            |</span><br><span class="line">+----+-------+-----+---------+---------------------+</span><br><span class="line">|  1 | Ringo |  18 | manager | 2020-08-03 08:30:39 |</span><br><span class="line">+----+-------+-----+---------+---------------------+</span><br><span class="line">1 row in set (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 2、使用 MySQL 内置的函数</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SELECT * FROM `staffs` WHERE LEFT(`name`, 5) = <span class="string">&#x27;Ringo&#x27;</span>;</span></span><br><span class="line">+----+-------+-----+---------+---------------------+</span><br><span class="line">| id | name  | age | pos     | add_time            |</span><br><span class="line">+----+-------+-----+---------+---------------------+</span><br><span class="line">|  1 | Ringo |  18 | manager | 2020-08-03 08:30:39 |</span><br><span class="line">+----+-------+-----+---------+---------------------+</span><br><span class="line">1 row in set (0.00 sec)</span><br></pre></td></tr></table></figure>

<p>我们发现以上两条 SQL 的执行结果都是一样的，但是执行效率有没有差距呢？？？</p>
<p>通过分析两条 SQL 的执行计划来分析性能。</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803171857325.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JyaW5nb18=,size_16,color_FFFFFF,t_70" alt="explain"></p>
<p><strong>由此可见，在索引列上进行计算，会使索引失效。</strong></p>
<p><strong>口诀：索引列上不计算。</strong></p>
<h2 id="10-4-范围之后全失效"><a href="#10-4-范围之后全失效" class="headerlink" title="10.4.范围之后全失效"></a>10.4.范围之后全失效</h2><blockquote>
<p>案例</p>
</blockquote>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 用到了 idx_staffs_name_age_pos 索引中的 name，age，pos 字段 这是属于全值匹配的情况！！！*/</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="operator">=</span> <span class="string">&#x27;Ringo&#x27;</span> <span class="keyword">AND</span> `age` <span class="operator">=</span> <span class="number">18</span> <span class="keyword">AND</span> `pos` <span class="operator">=</span> <span class="string">&#x27;manager&#x27;</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 用到了 idx_staffs_name_age_pos 索引中的 name，age 字段，pos 字段索引失效 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="operator">=</span> <span class="string">&#x27;张三&#x27;</span> <span class="keyword">AND</span> `age` <span class="operator">&gt;</span> <span class="number">18</span> <span class="keyword">AND</span> `pos` <span class="operator">=</span> <span class="string">&#x27;dev&#x27;</span>;</span><br></pre></td></tr></table></figure>

<p>查看上述 SQL 的执行计划</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803173357787.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JyaW5nb18=,size_16,color_FFFFFF,t_70" alt="explain"></p>
<p><strong>由此可知，查询范围的字段使用到了索引，但是范围之后的索引字段会失效。</strong></p>
<p><strong>口诀：范围之后全失效。</strong></p>
<h2 id="10-5-覆盖索引尽量用"><a href="#10-5-覆盖索引尽量用" class="headerlink" title="10.5.覆盖索引尽量用"></a>10.5.覆盖索引尽量用</h2><p>在写 SQL 的不要使用<code>SELECT *</code>，用什么字段就查询什么字段。</p>
<blockquote>
<p>ps： select 具体字段名 得到的就是覆盖索引</p>
</blockquote>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 没有用到覆盖索引 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="operator">=</span> <span class="string">&#x27;Ringo&#x27;</span> <span class="keyword">AND</span> `age` <span class="operator">=</span> <span class="number">18</span> <span class="keyword">AND</span> `pos` <span class="operator">=</span> <span class="string">&#x27;manager&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 用到了覆盖索引 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> `name`, `age`, `pos` <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="operator">=</span> <span class="string">&#x27;Ringo&#x27;</span> <span class="keyword">AND</span> `age` <span class="operator">=</span> <span class="number">18</span> <span class="keyword">AND</span> `pos` <span class="operator">=</span> <span class="string">&#x27;manager&#x27;</span>;</span><br></pre></td></tr></table></figure>

<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803213031893.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JyaW5nb18=,size_16,color_FFFFFF,t_70" alt="使用覆盖索引"></p>
<p>**口诀：查询一定不用<code>*</code>**。</p>
<h2 id="10-6-不等有时会失效"><a href="#10-6-不等有时会失效" class="headerlink" title="10.6.不等有时会失效"></a>10.6.不等有时会失效</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 会使用到覆盖索引 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> `name`, `age`, `pos` <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="operator">!=</span> <span class="string">&#x27;Ringo&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 索引失效 全表扫描 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="operator">!=</span> <span class="string">&#x27;Ringo&#x27;</span>;</span><br></pre></td></tr></table></figure>



<h2 id="10-7-like-百分加右边"><a href="#10-7-like-百分加右边" class="headerlink" title="10.7.like 百分加右边"></a>10.7.like 百分加右边</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 索引失效 全表扫描 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="keyword">LIKE</span> <span class="string">&#x27;%ing%&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 索引失效 全表扫描 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="keyword">LIKE</span> <span class="string">&#x27;%ing&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用索引范围查询 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="keyword">LIKE</span> <span class="string">&#x27;Rin%&#x27;</span>;</span><br></pre></td></tr></table></figure>

<p><strong>口诀：<code>like</code>百分加右边。</strong></p>
<p>如果一定要使用<code>%like</code>，而且还要保证索引不失效，那么使用覆盖索引来编写 SQL。</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 使用到了覆盖索引 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> `id` <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="keyword">LIKE</span> <span class="string">&#x27;%in%&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用到了覆盖索引 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> `name` <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="keyword">LIKE</span> <span class="string">&#x27;%in%&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用到了覆盖索引 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> `age` <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="keyword">LIKE</span> <span class="string">&#x27;%in%&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用到了覆盖索引 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> `pos` <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="keyword">LIKE</span> <span class="string">&#x27;%in%&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用到了覆盖索引 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> `id`, `name` <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="keyword">LIKE</span> <span class="string">&#x27;%in%&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用到了覆盖索引 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> `id`, `age` <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="keyword">LIKE</span> <span class="string">&#x27;%in%&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用到了覆盖索引 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> `id`,`name`, `age`, `pos` <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="keyword">LIKE</span> <span class="string">&#x27;%in&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用到了覆盖索引 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> `id`, `name` <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `pos` <span class="keyword">LIKE</span> <span class="string">&#x27;%na&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 索引失效 全表扫描 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> `name`, `age`, `pos`, `add_time` <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="keyword">LIKE</span> <span class="string">&#x27;%in&#x27;</span>;</span><br></pre></td></tr></table></figure>

<p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200803220743206.png" alt="模糊查询百分号一定加前边"></p>
<p><strong>口诀：覆盖索引保两边。</strong></p>
<h2 id="10-8-字符要加单引号"><a href="#10-8-字符要加单引号" class="headerlink" title="10.8.字符要加单引号"></a>10.8.字符要加单引号</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 使用到了覆盖索引 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> `id`, `name` <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="operator">=</span> <span class="string">&#x27;Ringo&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 使用到了覆盖索引 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> `id`, `name` <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="operator">=</span> <span class="number">2000</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 索引失效 全表扫描 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `staffs` <span class="keyword">WHERE</span> `name` <span class="operator">=</span> <span class="number">2000</span>;</span><br></pre></td></tr></table></figure>

<p>这里 name = 2000 在 MySQL 中会发生强制类型转换，将数字转成字符串。</p>
<p><strong>口诀：字符要加单引号。</strong></p>
<h2 id="10-9-索引相关题目"><a href="#10-9-索引相关题目" class="headerlink" title="10.9.索引相关题目"></a>10.9.索引相关题目</h2><p><strong>假设 index(a,b,c)</strong></p>
<table>
<thead>
<tr>
<th>Where语句</th>
<th>索引是否被使用</th>
</tr>
</thead>
<tbody><tr>
<td>where a = 3</td>
<td>Y，使用到 a</td>
</tr>
<tr>
<td>where a = 3 and b = 5</td>
<td>Y，使用到 a，b</td>
</tr>
<tr>
<td>where a = 3 and b = 5 and c = 4</td>
<td>Y，使用到 a，b，c</td>
</tr>
<tr>
<td>where b = 3 或者 where b = 3 and c = 4 或者 where c = 4</td>
<td>N，没有用到 a 字段</td>
</tr>
<tr>
<td>where a = 3 and c = 5</td>
<td>使用到 a，但是没有用到 c，因为 b 断了</td>
</tr>
<tr>
<td>where a = 3 and b &gt; 4 and c = 5</td>
<td>使用到 a，b，但是没有用到 c，因为 c 在范围之后</td>
</tr>
<tr>
<td>where a = 3 and b like ‘kk%’ and c = 4</td>
<td>Y，a，b，c 都用到</td>
</tr>
<tr>
<td>where a = 3 and b like ‘%kk’ and c = 4</td>
<td>只用到 a</td>
</tr>
<tr>
<td>where a = 3 and b like ‘%kk%’ and c = 4</td>
<td>只用到 a</td>
</tr>
<tr>
<td>where a = 3 and b like ‘k%kk%’ and c = 4</td>
<td>Y，a，b，c 都用到</td>
</tr>
</tbody></table>
<h2 id="10-10-面试题分析"><a href="#10-10-面试题分析" class="headerlink" title="10.10.面试题分析"></a>10.10.面试题分析</h2><blockquote>
<p>数据准备</p>
</blockquote>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 创建表 */</span></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> `test03`(</span><br><span class="line">`id` <span class="type">INT</span> <span class="keyword">PRIMARY</span> KEY <span class="keyword">NOT</span> <span class="keyword">NULL</span> AUTO_INCREMENT,</span><br><span class="line">`c1` <span class="type">CHAR</span>(<span class="number">10</span>),</span><br><span class="line">`c2` <span class="type">CHAR</span>(<span class="number">10</span>),</span><br><span class="line">`c3` <span class="type">CHAR</span>(<span class="number">10</span>),</span><br><span class="line">`c4` <span class="type">CHAR</span>(<span class="number">10</span>),</span><br><span class="line">`c5` <span class="type">CHAR</span>(<span class="number">10</span>)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 插入数据 */</span></span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `test03`(`c1`,`c2`,`c3`,`c4`,`c5`) <span class="keyword">VALUES</span>(<span class="string">&#x27;a1&#x27;</span>,<span class="string">&#x27;a2&#x27;</span>,<span class="string">&#x27;a3&#x27;</span>,<span class="string">&#x27;a4&#x27;</span>,<span class="string">&#x27;a5&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `test03`(`c1`,`c2`,`c3`,`c4`,`c5`) <span class="keyword">VALUES</span>(<span class="string">&#x27;b1&#x27;</span>,<span class="string">&#x27;b22&#x27;</span>,<span class="string">&#x27;b3&#x27;</span>,<span class="string">&#x27;b4&#x27;</span>,<span class="string">&#x27;b5&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `test03`(`c1`,`c2`,`c3`,`c4`,`c5`) <span class="keyword">VALUES</span>(<span class="string">&#x27;c1&#x27;</span>,<span class="string">&#x27;c2&#x27;</span>,<span class="string">&#x27;c3&#x27;</span>,<span class="string">&#x27;c4&#x27;</span>,<span class="string">&#x27;c5&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `test03`(`c1`,`c2`,`c3`,`c4`,`c5`) <span class="keyword">VALUES</span>(<span class="string">&#x27;d1&#x27;</span>,<span class="string">&#x27;d2&#x27;</span>,<span class="string">&#x27;d3&#x27;</span>,<span class="string">&#x27;d4&#x27;</span>,<span class="string">&#x27;d5&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `test03`(`c1`,`c2`,`c3`,`c4`,`c5`) <span class="keyword">VALUES</span>(<span class="string">&#x27;e1&#x27;</span>,<span class="string">&#x27;e2&#x27;</span>,<span class="string">&#x27;e3&#x27;</span>,<span class="string">&#x27;e4&#x27;</span>,<span class="string">&#x27;e5&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建复合索引 */</span></span><br><span class="line"><span class="keyword">CREATE</span> INDEX idx_test03_c1234 <span class="keyword">ON</span> `test03`(`c1`,`c2`,`c3`,`c4`);</span><br></pre></td></tr></table></figure>

<blockquote>
<p>题目</p>
</blockquote>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 最好索引怎么创建的，就怎么用，按照顺序使用，避免让 MySQL 再自己去翻译一次 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 1.全值匹配 用到索引 c1 c2 c3 c4 全字段 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span> `c2` <span class="operator">=</span> <span class="string">&#x27;a2&#x27;</span> <span class="keyword">AND</span> `c3` <span class="operator">=</span> <span class="string">&#x27;a3&#x27;</span> <span class="keyword">AND</span> `c4` <span class="operator">=</span> <span class="string">&#x27;a4&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 2.用到索引 c1 c2 c3 c4 全字段 MySQL 的查询优化器会优化 SQL 语句的顺序*/</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span> `c2` <span class="operator">=</span> <span class="string">&#x27;a2&#x27;</span> <span class="keyword">AND</span> `c4` <span class="operator">=</span> <span class="string">&#x27;a4&#x27;</span> <span class="keyword">AND</span> `c3` <span class="operator">=</span> <span class="string">&#x27;a3&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 3.用到索引 c1 c2 c3 c4 全字段 MySQL 的查询优化器会优化 SQL 语句的顺序*/</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c4` <span class="operator">=</span> <span class="string">&#x27;a4&#x27;</span> <span class="keyword">AND</span> `c3` <span class="operator">=</span> <span class="string">&#x27;a3&#x27;</span> <span class="keyword">AND</span> `c2` <span class="operator">=</span> <span class="string">&#x27;a2&#x27;</span> <span class="keyword">AND</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 4.用到索引 c1 c2 c3 字段，c4 字段失效，范围之后全失效 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span> `c2` <span class="operator">=</span> <span class="string">&#x27;a2&#x27;</span> <span class="keyword">AND</span> `c3` <span class="operator">&gt;</span> <span class="string">&#x27;a3&#x27;</span> <span class="keyword">AND</span> `c4` <span class="operator">=</span> <span class="string">&#x27;a4&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 5.用到索引 c1 c2 c3 c4 全字段 MySQL 的查询优化器会优化 SQL 语句的顺序*/</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span> `c2` <span class="operator">=</span> <span class="string">&#x27;a2&#x27;</span> <span class="keyword">AND</span> `c4` <span class="operator">&gt;</span> <span class="string">&#x27;a4&#x27;</span> <span class="keyword">AND</span> `c3` <span class="operator">=</span> <span class="string">&#x27;a3&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">  6.用到了索引 c1 c2 c3 三个字段, c1 和 c2 两个字段用于查找,  c3 字段用于排序了但是没有统计到 key_len 中，c4字段失效</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span> `c2` <span class="operator">=</span> <span class="string">&#x27;a2&#x27;</span> <span class="keyword">AND</span> `c4` <span class="operator">=</span> <span class="string">&#x27;a4&#x27;</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> `c3`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 7.用到了索引 c1 c2 c3 三个字段，c1 和 c2 两个字段用于查找, c3 字段用于排序了但是没有统计到 key_len 中*/</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span> `c2` <span class="operator">=</span> <span class="string">&#x27;a2&#x27;</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> `c3`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">   8.用到了索引 c1 c2 两个字段，c4 失效，c1 和 c2 两个字段用于查找，c4 字段排序产生了 Using filesort 说明排序没有用到 c4 字段 </span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span> `c2` <span class="operator">=</span> <span class="string">&#x27;a2&#x27;</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> `c4`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 9.用到了索引 c1 c2 c3 三个字段，c1 用于查找，c2 和 c3 用于排序 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span> `c5` <span class="operator">=</span> <span class="string">&#x27;a5&#x27;</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> `c2`, `c3`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 10.用到了 c1 一个字段，c1 用于查找，c3 和 c2 两个字段索引失效，产生了 Using filesort */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span> `c5` <span class="operator">=</span> <span class="string">&#x27;a5&#x27;</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> `c3`, `c2`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 11.用到了 c1 c2 c3 三个字段，c1 c2 用于查找，c2 c3 用于排序 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span>  `c2` <span class="operator">=</span> <span class="string">&#x27;a2&#x27;</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> c2, c3;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 12.用到了 c1 c2 c3 三个字段，c1 c2 用于查找，c2 c3 用于排序 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span>  `c2` <span class="operator">=</span> <span class="string">&#x27;a2&#x27;</span> <span class="keyword">AND</span> `c5` <span class="operator">=</span> <span class="string">&#x27;a5&#x27;</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> c2, c3;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">   13.用到了 c1 c2 c3 三个字段，c1 c2 用于查找，c2 c3 用于排序 没有产生 Using filesort </span></span><br><span class="line"><span class="comment">      因为之前 c2 这个字段已经确定了是 &#x27;a2&#x27;了，这是一个常量，再去 ORDER BY c3,c2 这时候 c2 已经不用排序了！</span></span><br><span class="line"><span class="comment">      所以没有产生 Using filesort 和 (10) 进行对比学习！</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span> `c2` <span class="operator">=</span> <span class="string">&#x27;a2&#x27;</span> <span class="keyword">AND</span> `c5` <span class="operator">=</span> <span class="string">&#x27;a5&#x27;</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> c3, c2;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* GROUP BY 表面上是叫做分组，但是分组之前必定排序。 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 14.用到 c1 c2 c3 三个字段，c1 用于查找，c2 c3 用于排序，c4 失效 */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span> `c4` <span class="operator">=</span> <span class="string">&#x27;a4&#x27;</span> <span class="keyword">GROUP</span> <span class="keyword">BY</span> `c2`,`c3`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 15.用到 c1 这一个字段，c4 失效，c2 和 c3 排序失效产生了 Using filesort */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `test03` <span class="keyword">WHERE</span> `c1` <span class="operator">=</span> <span class="string">&#x27;a1&#x27;</span> <span class="keyword">AND</span> `c4` <span class="operator">=</span> <span class="string">&#x27;a4&#x27;</span> <span class="keyword">GROUP</span> <span class="keyword">BY</span> `c3`,`c2`;</span><br></pre></td></tr></table></figure>

<p><code>GROUP BY</code>基本上都需要进行排序，索引优化几乎和<code>ORDER BY</code>一致，但是<code>GROUP BY</code>会有临时表的产生。</p>
<h2 id="10-11-总结"><a href="#10-11-总结" class="headerlink" title="10.11.总结"></a>10.11.总结</h2><p>索引优化的一般性建议：</p>
<ul>
<li>对于单值索引，尽量选择针对当前<code>query</code>过滤性更好的索引。</li>
<li>在选择复合索引的时候，当前<code>query</code>中过滤性最好的字段在索引字段顺序中，位置越靠前越好。</li>
<li>在选择复合索引的时候，尽量选择可以能够包含当前<code>query</code>中的<code>where</code>子句中更多字段的索引。</li>
<li>尽可能通过分析统计信息和调整<code>query</code>的写法来达到选择合适索引的目的。</li>
</ul>
<p>口诀：</p>
<ul>
<li>带头大哥不能死。</li>
<li>中间兄弟不能断。</li>
<li>索引列上不计算。</li>
<li>范围之后全失效。</li>
<li>覆盖索引尽量用。</li>
<li>不等有时会失效。</li>
<li>like百分加右边。</li>
<li>字符要加单引号。</li>
<li>一般SQL少用or。</li>
</ul>
<h1 id="11-分析慢-SQL-的步骤"><a href="#11-分析慢-SQL-的步骤" class="headerlink" title="11.分析慢 SQL 的步骤"></a>11.分析慢 SQL 的步骤</h1><p>分析：</p>
<p>1、观察，至少跑 1 天，看看生产的慢 SQL 情况。</p>
<p>2、开启<strong>慢查询日志</strong>，设置阈值，比如超过 5 秒钟的就是慢 SQL，并将它抓取出来。</p>
<p>3、explain + 慢 SQL 分析。</p>
<p>4、show Profile 分析当前会话中语句执行的资源消耗情况。</p>
<p>5、运维经理 OR DBA，进行 MySQL 数据库服务器的参数调优。</p>
<p>总结（大纲）：</p>
<p>1、慢查询的开启并捕获。</p>
<p>2、explain + 慢 SQL 分析。</p>
<p>3、show Profile 查询 SQL 在 MySQL 数据库中的执行细节和生命周期情况。</p>
<p>4、MySQL 数据库服务器的参数调优。</p>
<h1 id="12-查询优化"><a href="#12-查询优化" class="headerlink" title="12.查询优化"></a>12.查询优化</h1><h2 id="12-1-小表驱动大表"><a href="#12-1-小表驱动大表" class="headerlink" title="12.1.小表驱动大表"></a>12.1.小表驱动大表</h2><blockquote>
<p>优化原则：对于 MySQL 数据库而言，永远都是小表驱动大表。</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* 举个例子：可以使用嵌套的 for 循环来理解小表驱动大表。</span></span><br><span class="line"><span class="comment">* 以下两个循环结果都是一样的，但是对于 MySQL 来说不一样，</span></span><br><span class="line"><span class="comment">* 第一种可以理解为，和 MySQL 建立 5 次连接每次查询 1000 次。</span></span><br><span class="line"><span class="comment">* 第一种可以理解为，和 MySQL 建立 1000 次连接每次查询 5 次。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">5</span>; i ++)&#123;</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">1</span>; j &lt;= <span class="number">1000</span>; j++)&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">1000</span>; i ++)&#123;</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">1</span>; j &lt;= <span class="number">5</span>; j++)&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>IN 和 EXISTS</p>
</blockquote>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 优化原则：小表驱动大表，即小的数据集驱动大的数据集 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* IN 适合 B 表比 A 表数据小的情况*/</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `A` <span class="keyword">WHERE</span> `id` <span class="keyword">IN</span> (<span class="keyword">SELECT</span> `id` <span class="keyword">FROM</span> `B`)</span><br><span class="line"></span><br><span class="line"><span class="comment">/* EXISTS 适合 B 表比 A 表数据大的情况 */</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `A` <span class="keyword">WHERE</span> <span class="keyword">EXISTS</span> (<span class="keyword">SELECT</span> <span class="number">1</span> <span class="keyword">FROM</span> `B` <span class="keyword">WHERE</span> `B`.id <span class="operator">=</span> `A`.id);</span><br></pre></td></tr></table></figure>

<p><strong>EXISTS：</strong></p>
<ul>
<li>语法：<code>SELECT....FROM tab WHERE EXISTS(subquery);</code>该语法可以理解为：</li>
<li>该语法可以理解为：将主查询的数据，放到子查询中做条件验证，根据验证结果（<code>true</code>或是<code>false</code>）来决定主查询的数据结果是否得以保留。</li>
</ul>
<p><strong>提示：</strong></p>
<ul>
<li><code>EXISTS(subquery)</code>子查询只返回<code>true</code>或者<code>false</code>，因此子查询中的<code>SELECT *</code>可以是<code>SELECT 1 OR SELECT X</code>，它们并没有区别。</li>
<li><code>EXISTS(subquery)</code>子查询的实际执行过程可能经过了优化而不是我们理解上的逐条对比，如果担心效率问题，可进行实际检验以确定是否有效率问题。</li>
<li><code>EXISTS(subquery)</code>子查询往往也可以用条件表达式，其他子查询或者<code>JOIN</code>替代，何种最优需要具体问题具体分析。</li>
</ul>
<h2 id="12-2-ORDER-BY优化"><a href="#12-2-ORDER-BY优化" class="headerlink" title="12.2.ORDER BY优化"></a>12.2.ORDER BY优化</h2><blockquote>
<p>数据准备</p>
</blockquote>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> `talA`(</span><br><span class="line">`age` <span class="type">INT</span>,</span><br><span class="line">`birth` <span class="type">TIMESTAMP</span> <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="built_in">CURRENT_TIMESTAMP</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `talA`(`age`) <span class="keyword">VALUES</span>(<span class="number">18</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `talA`(`age`) <span class="keyword">VALUES</span>(<span class="number">19</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `talA`(`age`) <span class="keyword">VALUES</span>(<span class="number">20</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `talA`(`age`) <span class="keyword">VALUES</span>(<span class="number">21</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `talA`(`age`) <span class="keyword">VALUES</span>(<span class="number">22</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `talA`(`age`) <span class="keyword">VALUES</span>(<span class="number">23</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `talA`(`age`) <span class="keyword">VALUES</span>(<span class="number">24</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> `talA`(`age`) <span class="keyword">VALUES</span>(<span class="number">25</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 创建索引 */</span></span><br><span class="line"><span class="keyword">CREATE</span> INDEX idx_talA_age_birth <span class="keyword">ON</span> `talA`(`age`, `birth`);</span><br></pre></td></tr></table></figure>

<blockquote>
<p>案例</p>
</blockquote>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 1.使用索引进行排序了 不会产生 Using filesort */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `talA` <span class="keyword">WHERE</span> `age` <span class="operator">&gt;</span> <span class="number">20</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> `age`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 2.使用索引进行排序了 不会产生 Using filesort */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `talA` <span class="keyword">WHERE</span> `age` <span class="operator">&gt;</span> <span class="number">20</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> `age`,`birth`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 3.没有使用索引进行排序 产生了 Using filesort */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `talA` <span class="keyword">WHERE</span> `age` <span class="operator">&gt;</span> <span class="number">20</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> `birth`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 4.没有使用索引进行排序 产生了 Using filesort */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `talA` <span class="keyword">WHERE</span> `age` <span class="operator">&gt;</span> <span class="number">20</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> `birth`,`age`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 5.没有使用索引进行排序 产生了 Using filesort */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `talA` <span class="keyword">ORDER</span> <span class="keyword">BY</span> `birth`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 6.没有使用索引进行排序 产生了 Using filesort */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `talA` <span class="keyword">WHERE</span> `birth` <span class="operator">&gt;</span> <span class="string">&#x27;2020-08-04 07:42:21&#x27;</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> `birth`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 7.使用索引进行排序了 不会产生 Using filesort */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `talA` <span class="keyword">WHERE</span> `birth` <span class="operator">&gt;</span> <span class="string">&#x27;2020-08-04 07:42:21&#x27;</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> `age`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 8.没有使用索引进行排序 产生了 Using filesort */</span></span><br><span class="line">EXPLAIN <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> `talA` <span class="keyword">ORDER</span> <span class="keyword">BY</span> `age` <span class="keyword">ASC</span>, `birth` <span class="keyword">DESC</span>;</span><br></pre></td></tr></table></figure>

<p><code>ORDER BY</code>子句，尽量使用索引排序，避免使用<code>Using filesort</code>排序。</p>
<p>MySQL 支持两种方式的排序，<code>FileSort</code>和<code>Index</code>，<code>Index</code>的效率高，它指 MySQL 扫描索引本身完成排序。<code>FileSort</code>方式效率较低。</p>
<p><code>ORDER BY</code>满足两情况，会使用<code>Index</code>方式排序：</p>
<ul>
<li><code>ORDER BY</code>语句使用索引最左前列。</li>
<li>使用<code>WHERE</code>子句与<code>ORDER BY</code>子句条件列组合满足索引最左前列。</li>
</ul>
<p><strong>结论：尽可能在索引列上完成排序操作，遵照索引建的最佳左前缀原则。</strong></p>
<blockquote>
<p>如果不在索引列上，File Sort 有两种算法：MySQL 就要启动双路排序算法和单路排序算法</p>
</blockquote>
<p>1、双路排序算法：MySQL 4.1 之前使用双路排序，字面意思就是两次扫描磁盘，最终得到数据，读取行指针和<code>ORDER BY</code>列，対他们进行排序，然后扫描已经排序好的列表，按照列表中的值重新从列表中读取对应的数据输出。<strong>一句话，从磁盘取排序字段，在<code>buffer</code>中进行排序，再从磁盘取其他字段。</strong></p>
<p>取一批数据，要对磁盘进行两次扫描，众所周知，IO 是很耗时的，所以在 MySQL 4.1 之后，出现了改进的算法，就是单路排序算法。</p>
<p>2、单路排序算法：从磁盘读取查询需要的所有列，按照<code>ORDER BY</code>列在<code>buffer</code>対它们进行排序，然后扫描排序后的列表进行输出，它的效率更快一些，<strong>避免了第二次读取数据</strong>。并且把随机 IO 变成了顺序 IO，但是它会使用更多的空间，因为它把每一行都保存在内存中了。</p>
<p>由于单路排序算法是后出的，总体而言效率好过双路排序算法。</p>
<p>但是单路排序算法有问题：如果<code>SortBuffer</code>缓冲区太小，导致从磁盘中读取所有的列不能完全保存在<code>SortBuffer</code>缓冲区中，这时候单路复用算法就会出现问题，反而性能不如双路复用算法。</p>
<p><strong>单路复用算法的优化策略：</strong></p>
<ul>
<li>增大<code>sort_buffer_size</code>参数的设置。</li>
<li>增大<code>max_length_for_sort_data</code>参数的设置。</li>
</ul>
<p><strong>提高 ORDER BY 排序的速度：</strong></p>
<ul>
<li><p><code>ORDER BY</code>时使用<code>SELECT *</code>是大忌，查什么字段就写什么字段，这点非常重要。在这里的影响是：</p>
<ul>
<li>当查询的字段大小总和小于<code>max_length_for_sort_data</code>而且排序字段不是<code>TEXT|BLOB</code>类型时，会使用单路排序算法，否则使用多路排序算法。</li>
<li>两种排序算法的数据都有可能超出<code>sort_buffer</code>缓冲区的容量，超出之后，会创建<code>tmp</code>临时文件进行合并排序，导致多次 IO，但是单路排序算法的风险会更大一些，所以要增大<code>sort_buffer_size</code>参数的设置。</li>
</ul>
</li>
<li><p>尝试提高<code>sort_buffer_size</code>：不管使用哪种算法，提高这个参数都会提高效率，当然，要根据系统的能力去提高，因为这个参数是针对每个进程的。</p>
</li>
<li><p>尝试提高<code>max_length_for_sort_data</code>：提高这个参数，会增加用单路排序算法的概率。但是如果设置的太高，数据总容量<code>sort_buffer_size</code>的概率就增大，明显症状是高的磁盘 IO 活动和低的处理器使用率。</p>
</li>
</ul>
<h2 id="12-3-GORUP-BY-优化"><a href="#12-3-GORUP-BY-优化" class="headerlink" title="12.3.GORUP BY 优化"></a>12.3.GORUP BY 优化</h2><ul>
<li><p><code>GROUP BY</code>实质是先排序后进行分组，遵照索引建的最佳左前缀。</p>
</li>
<li><p>当无法使用索引列时，会使用<code>Using filesort</code>进行排序，增大<code>max_length_for_sort_data</code>参数的设置和增大<code>sort_buffer_size</code>参数的设置，会提高性能。</p>
</li>
<li><p><code>WHERE</code>执行顺序高于<code>HAVING</code>，能写在<code>WHERE</code>限定条件里的就不要写在<code>HAVING</code>中了。</p>
</li>
</ul>
<h2 id="12-4-总结"><a href="#12-4-总结" class="headerlink" title="12.4.总结"></a>12.4.总结</h2><p><strong>为排序使用索引</strong></p>
<ul>
<li>MySQL 两种排序方式：<code>Using filesort</code>和<code>Index</code>扫描有序索引排序。</li>
<li>MySQL 能为排序与查询使用相同的索引，创建的索引既可以用于排序也可以用于查询。</li>
</ul>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 创建a b c三个字段的索引 */</span></span><br><span class="line">idx_table_a_b_c(a, b, c)</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 1.ORDER BY 能使用索引最左前缀 */</span></span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> a;</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> a, b;</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> a, b, c;</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> a <span class="keyword">DESC</span>, b <span class="keyword">DESC</span>, c <span class="keyword">DESC</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 2.如果 WHERE 子句中使用索引的最左前缀定义为常量，则 ORDER BY 能使用索引 */</span></span><br><span class="line"><span class="keyword">WHERE</span> a <span class="operator">=</span> <span class="string">&#x27;Ringo&#x27;</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> b, c;</span><br><span class="line"><span class="keyword">WHERE</span> a <span class="operator">=</span> <span class="string">&#x27;Ringo&#x27;</span> <span class="keyword">AND</span> b <span class="operator">=</span> <span class="string">&#x27;Tangs&#x27;</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> c;</span><br><span class="line"><span class="keyword">WHERE</span> a <span class="operator">=</span> <span class="string">&#x27;Ringo&#x27;</span> <span class="keyword">AND</span> b <span class="operator">&gt;</span> <span class="number">2000</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> b, c;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 3.不能使用索引进行排序 */</span></span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> a <span class="keyword">ASC</span>, b <span class="keyword">DESC</span>, c <span class="keyword">DESC</span>;  <span class="comment">/* 排序不一致 */</span></span><br><span class="line"><span class="keyword">WHERE</span> g <span class="operator">=</span> const <span class="keyword">ORDER</span> <span class="keyword">BY</span> b, c;   <span class="comment">/* 丢失 a 字段索引 */</span></span><br><span class="line"><span class="keyword">WHERE</span> a <span class="operator">=</span> const <span class="keyword">ORDER</span> <span class="keyword">BY</span> c;     <span class="comment">/* 丢失 b 字段索引 */</span></span><br><span class="line"><span class="keyword">WHERE</span> a <span class="operator">=</span> const <span class="keyword">ORDER</span> <span class="keyword">BY</span> a, d;   <span class="comment">/* d 字段不是索引的一部分 */</span></span><br><span class="line"><span class="keyword">WHERE</span> a <span class="keyword">IN</span> (...) <span class="keyword">ORDER</span> <span class="keyword">BY</span> b, c;  <span class="comment">/* 对于排序来说，多个相等条件 (a=1 or a=2) 也是范围查询 */</span></span><br></pre></td></tr></table></figure>

<h1 id="13-慢查询日志"><a href="#13-慢查询日志" class="headerlink" title="13.慢查询日志"></a>13.慢查询日志</h1><h2 id="13-1-基本介绍"><a href="#13-1-基本介绍" class="headerlink" title="13.1.基本介绍"></a>13.1.基本介绍</h2><blockquote>
<p>慢查询日志是什么？</p>
</blockquote>
<ul>
<li>MySQL 的慢查询日志是 MySQL 提供的一种日志记录，它用来记录在 MySQL 中响应时间超过阈值的语句，具体指运行时间超过<code>long_query_time</code>值的 SQL，则会被记录到慢查询日志中。</li>
<li><code>long_query_time</code>的默认值为 10，意思是运行 10 秒以上的语句。</li>
<li>由慢查询日志来查看哪些 SQL 超出了我们的最大忍耐时间值，比如一条 SQL 执行超过 5 秒钟，我们就算慢SQL，希望能收集超过 5 秒钟的 SQL，结合之前<code>explain</code>进行全面分析。</li>
</ul>
<blockquote>
<p>特别说明</p>
</blockquote>
<p><strong>默认情况下，MySQL 数据库没有开启慢查询日志，</strong>需要我们手动来设置这个参数。</p>
<p><strong>当然，如果不是调优需要的话，一般不建议启动该参数</strong>，因为开启慢查询日志会或多或少带来一定的性能影响。慢查询日志支持将日志记录写入文件。</p>
<blockquote>
<p>查看慢查询日志是否开以及如何开启</p>
</blockquote>
<ul>
<li><p>查看慢查询日志是否开启：<code>SHOW VARIABLES LIKE &#39;%slow_query_log%&#39;;</code>。</p>
</li>
<li><p>开启慢查询日志：<code>SET GLOBAL slow_query_log = 1;</code>。<strong>使用该方法开启 MySQL 的慢查询日志只对当前数据库生效，如果 MySQL 重启后会失效。</strong></p>
</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1、查看慢查询日志是否开启</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SHOW VARIABLES LIKE <span class="string">&#x27;%slow_query_log%&#x27;</span>;</span></span><br><span class="line">+---------------------+--------------------------------------+</span><br><span class="line">| Variable_name       | Value                                |</span><br><span class="line">+---------------------+--------------------------------------+</span><br><span class="line">| slow_query_log      | OFF                                  |</span><br><span class="line">| slow_query_log_file | /var/lib/mysql/1dcb5644392c-slow.log |</span><br><span class="line">+---------------------+--------------------------------------+</span><br><span class="line">2 rows in set (0.01 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 2、开启慢查询日志</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SET GLOBAL slow_query_log = 1;</span></span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br></pre></td></tr></table></figure>



<p>如果要使慢查询日志永久开启，需要修改<code>my.cnf</code>文件，在<code>[mysqld]</code>下增加修改参数。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> my.cnf</span></span><br><span class="line">[mysqld]</span><br><span class="line"><span class="meta">#</span><span class="bash"> 1.这个是开启慢查询。注意 ON 需要大写</span></span><br><span class="line">slow_query_log=ON  </span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 2.这个是存储慢查询的日志文件。这个文件不存在的话，需要自己创建</span></span><br><span class="line">slow_query_log_file=/var/lib/mysql/slow.log</span><br></pre></td></tr></table></figure>



<blockquote>
<p>开启了慢查询日志后，什么样的 SQL 才会被记录到慢查询日志里面呢？</p>
</blockquote>
<p>这个是由参数<code>long_query_time</code>控制的，默认情况下<code>long_query_time</code>的值为 10 秒。</p>
<p>MySQL 中查看<code>long_query_time</code>的时间：<code>SHOW VARIABLES LIKE &#39;long_query_time%&#39;;</code>。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 查看 long_query_time 默认是 10 秒</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 只有 SQL 的执行时间 &gt;10 才会被记录</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SHOW VARIABLES LIKE <span class="string">&#x27;long_query_time%&#x27;</span>;</span></span><br><span class="line">+-----------------+-----------+</span><br><span class="line">| Variable_name   | Value     |</span><br><span class="line">+-----------------+-----------+</span><br><span class="line">| long_query_time | 10.000000 |</span><br><span class="line">+-----------------+-----------+</span><br><span class="line">1 row in set (0.00 sec)</span><br></pre></td></tr></table></figure>



<p>修改<code>long_query_time</code>的时间，需要在<code>my.cnf</code>修改配置文件</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[mysqld]</span><br><span class="line"><span class="meta">#</span><span class="bash"> 这个是设置慢查询的时间，我设置的为 1 秒</span></span><br><span class="line">long_query_time=1</span><br></pre></td></tr></table></figure>



<p>查询慢查询日志的总记录条数：<code>SHOW GLOBAL STATUS LIKE &#39;%Slow_queries%&#39;;</code>。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SHOW GLOBAL STATUS LIKE <span class="string">&#x27;%Slow_queries%&#x27;</span>;</span></span><br><span class="line">+---------------+-------+</span><br><span class="line">| Variable_name | Value |</span><br><span class="line">+---------------+-------+</span><br><span class="line">| Slow_queries  | 3     |</span><br><span class="line">+---------------+-------+</span><br><span class="line">1 row in set (0.00 sec)</span><br></pre></td></tr></table></figure>

<h2 id="13-2-日志分析工具"><a href="#13-2-日志分析工具" class="headerlink" title="13.2.日志分析工具"></a>13.2.日志分析工具</h2><p>日志分析工具<code>mysqldumpslow</code>：在生产环境中，如果要手工分析日志，查找、分析 SQL，显然是个体力活，MySQL 提供了日志分析工具<code>mysqldumpslow</code>。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1、mysqldumpslow --<span class="built_in">help</span> 来查看 mysqldumpslow 的帮助信息</span></span><br><span class="line">root@1dcb5644392c:/usr/bin  # mysqldumpslow --help</span><br><span class="line">Usage: mysqldumpslow [ OPTS... ] [ LOGS... ]</span><br><span class="line"></span><br><span class="line">Parse and summarize the MySQL slow query log. Options are</span><br><span class="line"></span><br><span class="line">  --verbose    verbose</span><br><span class="line">  --debug      debug</span><br><span class="line">  --help      write this text to standard output</span><br><span class="line"></span><br><span class="line">  -v           verbose</span><br><span class="line">  -d           debug</span><br><span class="line">  -s ORDER     what to sort by (al, at, ar, c, l, r, t), &#x27;at&#x27; is default  # 按照何种方式排序</span><br><span class="line">                al: average lock time        # 平均锁定时间</span><br><span class="line">                ar: average rows sent 		   # 平均返回记录数</span><br><span class="line">                at: average query time 		   # 平均查询时间</span><br><span class="line">                 c: count  		# 访问次数</span><br><span class="line">                 l: lock time   # 锁定时间</span><br><span class="line">                 r: rows sent   # 返回记录</span><br><span class="line">                 t: query time  # 查询时间 </span><br><span class="line">  -r           reverse the sort order (largest last instead of first)</span><br><span class="line">  -t NUM       just show the top n queries  # 返回前面多少条记录</span><br><span class="line">  -a           don&#x27;t abstract all numbers to N and strings to &#x27;S&#x27;</span><br><span class="line">  -n NUM       abstract numbers with at least n digits within names</span><br><span class="line">  -g PATTERN   grep: only consider stmts that include this string  # 只考虑包含此字符串的语句</span><br><span class="line">  -h HOSTNAME  hostname of db server for *-slow.log filename (can be wildcard),</span><br><span class="line">               default is &#x27;*&#x27;, i.e. match all</span><br><span class="line">  -i NAME      name of server instance (if using mysql.server startup script)</span><br><span class="line">  -l           don&#x27;t subtract lock time from total time</span><br><span class="line">  </span><br><span class="line"><span class="meta">#</span><span class="bash"> 2、 案例</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 2.1、得到返回记录集最多的 10 个 SQL</span></span><br><span class="line">mysqldumpslow -s r -t 10 /var/lib/mysql/slow.log</span><br><span class="line"> </span><br><span class="line"><span class="meta">#</span><span class="bash"> 2.2、得到访问次数最多的 10 个 SQL</span></span><br><span class="line">mysqldumpslow -s c -t 10 /var/lib/mysql/slow.log</span><br><span class="line"> </span><br><span class="line"><span class="meta">#</span><span class="bash"> 2.3、得到按照时间排序的前 10 条里面含有左连接的查询语句</span></span><br><span class="line">mysqldumpslow -s t -t 10 -g &quot;left join&quot; /var/lib/mysql/slow.log</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 2.4、另外建议使用这些命令时结合|和 more 使用，否则出现爆屏的情况</span></span><br><span class="line">mysqldumpslow -s r -t 10 /var/lib/mysql/slow.log | more</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h1 id="14-批量插入数据脚本"><a href="#14-批量插入数据脚本" class="headerlink" title="14.批量插入数据脚本"></a>14.批量插入数据脚本</h1><h2 id="14-1-环境准备"><a href="#14-1-环境准备" class="headerlink" title="14.1.环境准备"></a>14.1.环境准备</h2><blockquote>
<p>1、建表 SQL</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;* 1.dept表 *&#x2F;</span><br><span class="line">CREATE TABLE &#96;dept&#96; (</span><br><span class="line">  &#96;id&#96; int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT &#39;主键&#39;,</span><br><span class="line">  &#96;deptno&#96; int(10) unsigned NOT NULL DEFAULT &#39;0&#39; COMMENT &#39;部门id&#39;,</span><br><span class="line">  &#96;dname&#96; varchar(20) NOT NULL DEFAULT &#39;&#39; COMMENT &#39;部门名字&#39;,</span><br><span class="line">  &#96;loc&#96; varchar(13) NOT NULL DEFAULT &#39;&#39; COMMENT &#39;部门地址&#39;,</span><br><span class="line">  PRIMARY KEY (&#96;id&#96;)</span><br><span class="line">) ENGINE&#x3D;InnoDB DEFAULT CHARSET&#x3D;utf8 COMMENT&#x3D;&#39;部门表&#39;</span><br><span class="line"></span><br><span class="line">&#x2F;* 2.emp表 *&#x2F;</span><br><span class="line">CREATE TABLE &#96;emp&#96; (</span><br><span class="line">  &#96;id&#96; int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT &#39;主键&#39;,</span><br><span class="line">  &#96;empno&#96; int(10) unsigned NOT NULL DEFAULT &#39;0&#39; COMMENT &#39;员工编号&#39;,</span><br><span class="line">  &#96;ename&#96; varchar(20) NOT NULL DEFAULT &#39;&#39; COMMENT &#39;员工名字&#39;,</span><br><span class="line">  &#96;job&#96; varchar(9) NOT NULL DEFAULT &#39;&#39; COMMENT &#39;职位&#39;,</span><br><span class="line">  &#96;mgr&#96; int(10) unsigned NOT NULL DEFAULT &#39;0&#39; COMMENT &#39;上级编号&#39;,</span><br><span class="line">  &#96;hiredata&#96; date NOT NULL COMMENT &#39;入职时间&#39;,</span><br><span class="line">  &#96;sal&#96; decimal(7,2) NOT NULL COMMENT &#39;薪水&#39;,</span><br><span class="line">  &#96;comm&#96; decimal(7,2) NOT NULL COMMENT &#39;分红&#39;,</span><br><span class="line">  &#96;deptno&#96; int(10) unsigned NOT NULL DEFAULT &#39;0&#39; COMMENT &#39;部门id&#39;,</span><br><span class="line">  PRIMARY KEY (&#96;id&#96;)</span><br><span class="line">) ENGINE&#x3D;InnoDB DEFAULT CHARSET&#x3D;utf8 COMMENT&#x3D;&#39;员工表&#39;</span><br></pre></td></tr></table></figure>



<blockquote>
<p>2、由于开启过慢查询日志，开启了<code>bin-log</code>，我们就必须为<code>function</code>指定一个参数，否则使用函数会报错。</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 在 mysql 中设置</span> </span><br><span class="line"><span class="meta">#</span><span class="bash"> log_bin_trust_function_creators 默认是关闭的 需要手动开启</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SHOW VARIABLES LIKE <span class="string">&#x27;log_bin_trust_function_creators&#x27;</span>;</span></span><br><span class="line">+---------------------------------+-------+</span><br><span class="line">| Variable_name                   | Value |</span><br><span class="line">+---------------------------------+-------+</span><br><span class="line">| log_bin_trust_function_creators | OFF   |</span><br><span class="line">+---------------------------------+-------+</span><br><span class="line">1 row in set (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SET GLOBAL log_bin_trust_function_creators=1;</span></span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br></pre></td></tr></table></figure>

<p>上述修改方式 MySQL 重启后会失效，在<code>my.cnf</code>配置文件下修改永久有效。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[mysqld]</span><br><span class="line">log_bin_trust_function_creators=ON</span><br></pre></td></tr></table></figure>

<h2 id="14-2-创建函数"><a href="#14-2-创建函数" class="headerlink" title="14.2.创建函数"></a>14.2.创建函数</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"># 1、函数：随机产生字符串 ，DECLARE &#x3D; 声明</span><br><span class="line">DELIMITER $$</span><br><span class="line">CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)</span><br><span class="line">BEGIN</span><br><span class="line">    DECLARE chars_str VARCHAR(100) DEFAULT &#39;abcdefghijklmnopqrstuvwsyzABCDEFGHIJKLMNOPQRSTUVWXYZ&#39;;</span><br><span class="line">    DECLARE return_str VARCHAR(255) DEFAULT &#39;&#39;;</span><br><span class="line">    DECLARE i INT DEFAULT 0;</span><br><span class="line">    WHILE i &lt; n DO</span><br><span class="line">    SET return_str &#x3D; CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));</span><br><span class="line">    SET i &#x3D; i + 1;</span><br><span class="line">    END WHILE;</span><br><span class="line">    RETURN return_str;</span><br><span class="line">END $$</span><br><span class="line"></span><br><span class="line"># 2、函数：随机产生部门编号</span><br><span class="line">DELIMITER $$</span><br><span class="line">CREATE FUNCTION rand_num() RETURNS INT(5)</span><br><span class="line">BEGIN</span><br><span class="line">    DECLARE i INT DEFAULT 0;</span><br><span class="line">    SET i &#x3D; FLOOR(100 + RAND() * 10);</span><br><span class="line">    RETURN i;</span><br><span class="line">END $$</span><br></pre></td></tr></table></figure>

<h2 id="14-3-创建存储过程"><a href="#14-3-创建存储过程" class="headerlink" title="14.3.创建存储过程"></a>14.3.创建存储过程</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"># 1、函数：向 dept 表批量插入</span><br><span class="line">DELIMITER $$</span><br><span class="line">CREATE PROCEDURE insert_dept(IN START INT(10),IN max_num INT(10))</span><br><span class="line">BEGIN</span><br><span class="line">DECLARE i INT DEFAULT 0;</span><br><span class="line">    SET autocommit &#x3D; 0;</span><br><span class="line">    REPEAT</span><br><span class="line">    SET i &#x3D; i + 1;</span><br><span class="line">    INSERT INTO dept(deptno,dname,loc) VALUES((START + i),rand_string(10),rand_string(8));</span><br><span class="line">    UNTIL i &#x3D; max_num</span><br><span class="line">    END REPEAT;</span><br><span class="line">    COMMIT;</span><br><span class="line">END $$</span><br><span class="line"></span><br><span class="line"># 2、函数：向 emp 表批量插入</span><br><span class="line">DELIMITER $$</span><br><span class="line">CREATE PROCEDURE insert_emp(IN START INT(10),IN max_num INT(10))</span><br><span class="line">BEGIN</span><br><span class="line">DECLARE i INT DEFAULT 0;</span><br><span class="line">    SET autocommit &#x3D; 0;</span><br><span class="line">    REPEAT</span><br><span class="line">    SET i &#x3D; i + 1;</span><br><span class="line">    INSERT INTO emp(empno,ename,job,mgr,hiredata,sal,comm,deptno) VALUES((START + i),rand_string(6),&#39;SALESMAN&#39;,0001,CURDATE(),2000,400,rand_num());</span><br><span class="line">    UNTIL i &#x3D; max_num</span><br><span class="line">    END REPEAT;</span><br><span class="line">    COMMIT;</span><br><span class="line">END $$</span><br></pre></td></tr></table></figure>

<h2 id="14-4-调用存储过程"><a href="#14-4-调用存储过程" class="headerlink" title="14.4.调用存储过程"></a>14.4.调用存储过程</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"># 1、调用存储过程向 dept 表插入 10 个部门。</span><br><span class="line">DELIMITER ;</span><br><span class="line">CALL insert_dept(100,10);</span><br><span class="line"></span><br><span class="line"># 2、调用存储过程向 emp 表插入50万条数据。</span><br><span class="line">DELIMITER ;</span><br><span class="line">CALL insert_emp(100001,500000);</span><br></pre></td></tr></table></figure>

<h1 id="15-Show-Profile"><a href="#15-Show-Profile" class="headerlink" title="15.Show Profile"></a>15.Show Profile</h1><blockquote>
<p>Show Profile 是什么？</p>
</blockquote>
<p><code>Show Profile</code>：MySQL 提供可以用来分析当前会话中语句执行的资源消耗情况。可以用于 SQL 的调优的测量。<strong>默认情况下，参数处于关闭状态，并保存最近 15 次的运行结果。</strong></p>
<blockquote>
<p>分析步骤</p>
</blockquote>
<p>1、是否支持，看看当前的 MySQL 版本是否支持。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 查看 Show Profile 功能是否开启</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SHOW VARIABLES LIKE <span class="string">&#x27;profiling&#x27;</span>;</span></span><br><span class="line">+---------------+-------+</span><br><span class="line">| Variable_name | Value |</span><br><span class="line">+---------------+-------+</span><br><span class="line">| profiling     | OFF   |</span><br><span class="line">+---------------+-------+</span><br><span class="line">1 row in set (0.00 sec)</span><br></pre></td></tr></table></figure>

<p>2、开启<code>Show Profile</code>功能，默认是关闭的，使用前需要开启。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 开启Show Profile功能</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SET profiling=ON;</span></span><br><span class="line">Query OK, 0 rows affected, 1 warning (0.00 sec)</span><br></pre></td></tr></table></figure>

<p>3、运行 SQL</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM &#96;emp&#96; GROUP BY &#96;id&#96;%10 LIMIT 150000;</span><br><span class="line"></span><br><span class="line">SELECT * FROM &#96;emp&#96; GROUP BY &#96;id&#96;%20 ORDER BY 5;</span><br></pre></td></tr></table></figure>

<p>4、查看结果，执行<code>SHOW PROFILES;</code></p>
<p><code>Duration</code>：持续时间。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SHOW PROFILES;</span></span><br><span class="line">+----------+------------+---------------------------------------------------+</span><br><span class="line">| Query_ID | Duration   | Query                                             |</span><br><span class="line">+----------+------------+---------------------------------------------------+</span><br><span class="line">|     1    | 0.00156100 | SHOW VARIABLES LIKE &#x27;profiling&#x27;                   |</span><br><span class="line">|     2    | 0.56296725 | SELECT * FROM `emp` GROUP BY `id`%10 LIMIT 150000 |</span><br><span class="line">|     3    | 0.52105825 | SELECT * FROM `emp` GROUP BY `id`%10 LIMIT 150000 |</span><br><span class="line">|     4    | 0.51279775 | SELECT * FROM `emp` GROUP BY `id`%20 ORDER BY 5   |</span><br><span class="line">+----------+------------+---------------------------------------------------+</span><br><span class="line">4 rows in set, 1 warning (0.00 sec)</span><br></pre></td></tr></table></figure>

<p>5、诊断 SQL，<code>SHOW PROFILE cpu,block io FOR QUERY Query_ID;</code></p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 这里的 3 是第四步中的 Query_ID。</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 可以在 SHOW PROFILE 中看到一条 SQL 中完整的生命周期。</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SHOW PROFILE cpu,block io FOR QUERY 3;</span></span><br><span class="line">+-----------------+----------+----------+------------+--------------+---------------+</span><br><span class="line">| Status          | Duration | CPU_user | CPU_system |       Block_ops_in|      Block_ops_out|</span><br><span class="line">+-----------------+----------+----------+------------+--------------+---------------+</span><br><span class="line">| starting         | 0.000097 | 0.000090 |   0.000002 |            0 |             0 |</span><br><span class="line">| checking permissions | 0.000010 | 0.000009 |   0.000000 |            0 |             0 |</span><br><span class="line">| Opening tables     | 0.000039 | 0.000058 |   0.000000 |            0 |             0 |</span><br><span class="line">| init            | 0.000046 | 0.000046 |   0.000000 |            0 |             0 |</span><br><span class="line">| System lock       | 0.000011 | 0.000000 |   0.000000 |            0 |             0 |</span><br><span class="line">| optimizing        | 0.000005 | 0.000000 |   0.000000 |            0 |             0 |</span><br><span class="line">| statistics        | 0.000023 | 0.000037 |   0.000000 |            0 |             0 |</span><br><span class="line">| preparing        | 0.000014 | 0.000000 |   0.000000 |            0 |             0 |</span><br><span class="line">| Creating tmp table  | 0.000041 | 0.000053 |   0.000000 |            0 |         0 |</span><br><span class="line">| Sorting result     | 0.000005 | 0.000000 |   0.000000 |            0 |             0 |</span><br><span class="line">| executing        | 0.000003 | 0.000000 |   0.000000 |            0 |             0 |</span><br><span class="line">| Sending data      | 0.520620 | 0.516267 |   0.000000 |            0 |             0 |</span><br><span class="line">| Creating sort index  | 0.000060 | 0.000051 |   0.000000 |            0 |             0 |</span><br><span class="line">| end            | 0.000006 | 0.000000 |   0.000000 |            0 |             0 |</span><br><span class="line">| query end        | 0.000011 | 0.000000 |   0.000000 |            0 |             0 |</span><br><span class="line">| removing tmp table  | 0.000006 | 0.000000 |   0.000000 |            0 |             0 |</span><br><span class="line">| query end        | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |</span><br><span class="line">| closing tables     | 0.000009 | 0.000000 |   0.000000 |            0 |             0 |</span><br><span class="line">| freeing items     | 0.000032 | 0.000064 |   0.000000 |            0 |             0 |</span><br><span class="line">| cleaning up       | 0.000019 | 0.000000 |   0.000000 |            0 |             0 |</span><br><span class="line">+-----------------+----------+----------+------------+--------------+---------------+</span><br><span class="line">20 rows in set, 1 warning (0.00 sec)</span><br></pre></td></tr></table></figure>

<p><code>Show Profile</code>查询参数备注：</p>
<ul>
<li><code>ALL</code>：显示所有的开销信息。</li>
<li><code>BLOCK IO</code>：显示块 IO 相关开销（通用）block = 阻塞。</li>
<li><code>CONTEXT SWITCHES</code>：上下文切换相关开销。</li>
<li><code>CPU</code>：显示 CPU 相关开销信息（通用）。</li>
<li><code>IPC</code>：显示发送和接收相关开销信息。</li>
<li><code>MEMORY</code>：显示内存相关开销信息。</li>
<li><code>PAGE FAULTS</code>：显示页面错误相关开销信息。</li>
<li><code>SOURCE</code>：显示和 Source_function。</li>
<li><code>SWAPS</code>：显示交换次数相关开销的信息。</li>
</ul>
<p>6、<code>Show Profile</code>查询列表，日常开发需要注意的结论：</p>
<ul>
<li><code>converting HEAP to MyISAM</code>：查询结果太大，内存都不够用了，往磁盘上搬了。</li>
<li><code>Creating tmp table</code>：创建临时表（拷贝数据到临时表，用完再删除），非常耗费数据库性能。</li>
<li><code>Copying to tmp table on disk</code>：把内存中的临时表复制到磁盘，危险！！！</li>
<li><code>locked</code>：死锁。</li>
</ul>
<h1 id="16-表锁-偏读"><a href="#16-表锁-偏读" class="headerlink" title="16.表锁(偏读)"></a>16.表锁(偏读)</h1><p><strong>表锁特点：</strong></p>
<ul>
<li>表锁偏向<code>MyISAM</code>存储引擎，开销小，加锁快，无死锁，锁定粒度大，发生锁冲突的概率最高，并发度最低。</li>
</ul>
<h2 id="16-1-环境准备"><a href="#16-1-环境准备" class="headerlink" title="16.1.环境准备"></a>16.1.环境准备</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"># 1、创建表</span><br><span class="line">CREATE TABLE &#96;mylock&#96;(</span><br><span class="line">&#96;id&#96; INT NOT NULL PRIMARY KEY AUTO_INCREMENT,</span><br><span class="line">&#96;name&#96; VARCHAR(20)</span><br><span class="line">)ENGINE&#x3D;MYISAM DEFAULT CHARSET&#x3D;utf8 COMMENT&#x3D;&#39;测试表锁&#39;;</span><br><span class="line"></span><br><span class="line"># 2、插入数据</span><br><span class="line">INSERT INTO &#96;mylock&#96;(&#96;name&#96;) VALUES(&#39;ZhangSan&#39;);</span><br><span class="line">INSERT INTO &#96;mylock&#96;(&#96;name&#96;) VALUES(&#39;LiSi&#39;);</span><br><span class="line">INSERT INTO &#96;mylock&#96;(&#96;name&#96;) VALUES(&#39;WangWu&#39;);</span><br><span class="line">INSERT INTO &#96;mylock&#96;(&#96;name&#96;) VALUES(&#39;ZhaoLiu&#39;);</span><br></pre></td></tr></table></figure>

<h2 id="16-2-锁表的命令"><a href="#16-2-锁表的命令" class="headerlink" title="16.2.锁表的命令"></a>16.2.锁表的命令</h2><blockquote>
<p>1、查看数据库表锁的命令。</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># 查看数据库表锁的命令</span><br><span class="line">SHOW OPEN TABLES;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、给<code>mylock</code>表上读锁，给<code>book</code>表上写锁。</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"># 给 mylock 表上读锁，给 book 表上写锁</span><br><span class="line">LOCK TABLE &#96;mylock&#96; READ, &#96;book&#96; WRITE;</span><br><span class="line"></span><br><span class="line"># 查看当前表的状态</span><br><span class="line">mysql&gt; SHOW OPEN TABLES;</span><br><span class="line">+--------------------+------------------------------------------------------+-------+</span><br><span class="line">| Database           | Table   |  In_use |  Name_locked |</span><br><span class="line">+--------------------+------------------------------------------------------+-------+</span><br><span class="line">| sql_analysis       | book    |     1   |        0     |</span><br><span class="line">| sql_analysis       | mylock  |     1   |        0     |</span><br><span class="line">+--------------------+------------------------------------------------------+-------+</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、释放表锁。</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"># 释放给表添加的锁</span><br><span class="line">UNLOCK TABLES;</span><br><span class="line"></span><br><span class="line"># 查看当前表的状态</span><br><span class="line">mysql&gt; SHOW OPEN TABLES;</span><br><span class="line">+--------------------+-------------------------------------+--------+-------------+</span><br><span class="line">| Database           | Table     |   In_use |    Name_locked |</span><br><span class="line">+--------------------+-------------------------------------+--------+-------------+</span><br><span class="line">| sql_analysis       | book      |      0   |           0 |</span><br><span class="line">| sql_analysis       | mylock    |      0   |           0 |</span><br><span class="line">+--------------------+-------------------------------------+--------+-------------+</span><br></pre></td></tr></table></figure>

<h2 id="16-3-读锁案例"><a href="#16-3-读锁案例" class="headerlink" title="16.3.读锁案例"></a>16.3.读锁案例</h2><blockquote>
<p>1、打开两个会话，<code>SESSION1</code>为<code>mylock</code>表添加读锁。</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># 为 mylock 表添加读锁</span><br><span class="line">LOCK TABLE &#96;mylock&#96; READ;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、打开两个会话，<code>SESSION1</code>是否可以读自己锁的表？是否可以修改自己锁的表数据？是否可以读其他的表？那么<code>SESSION2</code>呢？</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> SESSION1</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 问题1：SESSION1 为 mylock 表加了读锁，可以读 mylock 表！</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SELECT * FROM `mylock`;</span></span><br><span class="line">+----+----------+</span><br><span class="line">| id  | name     |</span><br><span class="line">+----+----------+</span><br><span class="line">|  1 | ZhangSan  |</span><br><span class="line">|  2 | LiSi     |</span><br><span class="line">|  3 | WangWu   |</span><br><span class="line">|  4 | ZhaoLiu   |</span><br><span class="line">+----+----------+</span><br><span class="line">4 rows in set (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 问题2：SESSION1 为 mylock 表加了读锁，不可以修改 mylock 表数据！</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> UPDATE `mylock` SET `name` = <span class="string">&#x27;abc&#x27;</span> WHERE `id` = 1;</span></span><br><span class="line">ERROR 1099 (HY000): Table &#x27;mylock&#x27; was locked with a READ lock and can&#x27;t be updated</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 问题3：SESSION1 为 mylock 表加了读锁，不可以读其他的表！</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SELECT * FROM `book`;</span></span><br><span class="line">ERROR 1100 (HY000): Table &#x27;book&#x27; was not locked with LOCK TABLES</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> SESSION2</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 问题1：SESSION1 为 mylock 表加了读锁，SESSION2 可以读 mylock 表！</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SELECT * FROM `mylock`;</span></span><br><span class="line">+----+----------+</span><br><span class="line">| id | name     |</span><br><span class="line">+----+----------+</span><br><span class="line">|  1 | ZhangSan  |</span><br><span class="line">|  2 | LiSi     |</span><br><span class="line">|  3 | WangWu   |</span><br><span class="line">|  4 | ZhaoLiu   |</span><br><span class="line">+----+----------+</span><br><span class="line">4 rows in set (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 问题2：SESSION1 为 mylock 表加了读锁，SESSION2 修改 mylock 表数据会被阻塞，需要等待 SESSION1 释放mylock 表！</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> UPDATE `mylock` SET `name` = <span class="string">&#x27;abc&#x27;</span> WHERE `id` = 1;</span></span><br><span class="line">^C^C -- query aborted # 查询中止</span><br><span class="line">ERROR 1317 (70100): Query execution was interrupted</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 问题3：SESSION1 为 mylock 表加了读锁，SESSION2 可以读其他表！</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SELECT * FROM `book`;</span></span><br><span class="line">+--------+------+</span><br><span class="line">| bookid |  card  |</span><br><span class="line">+--------+------+</span><br><span class="line">|    1  |    1  |</span><br><span class="line">|    7  |    4  |</span><br><span class="line">|    8  |    4  |</span><br><span class="line">|    9  |    5  |</span><br><span class="line">|    5  |    6  |</span><br><span class="line">|    17 |    6  |</span><br><span class="line">|    15 |    8  |</span><br><span class="line">+--------+------+</span><br><span class="line">24 rows in set (0.00 sec)</span><br></pre></td></tr></table></figure>



<h2 id="16-4-写锁案例"><a href="#16-4-写锁案例" class="headerlink" title="16.4.写锁案例"></a>16.4.写锁案例</h2><blockquote>
<p>1、打开两个会话，<code>SESSION1</code>为<code>mylock</code>表添加写锁。</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># 为 mylock 表添加写锁</span><br><span class="line">LOCK TABLE &#96;mylock&#96; WRITE;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、打开两个会话，<code>SESSION1</code>是否可以读自己锁的表？是否可以修改自己锁的表？是否可以读其他的表？那么<code>SESSION2</code>呢？</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> SESSION1</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 问题1：SESSION1 为 mylock 表加了写锁，可以读 mylock 的表！</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SELECT * FROM `mylock`;</span></span><br><span class="line">+----+----------+</span><br><span class="line">| id | name    |</span><br><span class="line">+----+----------+</span><br><span class="line">|  1 | ZhangSan |</span><br><span class="line">|  2 | LiSi    |</span><br><span class="line">|  3 | WangWu  |</span><br><span class="line">|  4 | ZhaoLiu  |</span><br><span class="line">+----+----------+</span><br><span class="line">4 rows in set (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 问题2：SESSION1 为 mylock 表加了写锁，可以修改 mylock 表!</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> UPDATE `mylock` SET `name` = <span class="string">&#x27;abc&#x27;</span> WHERE `id` = 1;</span></span><br><span class="line">Query OK, 1 row affected (0.00 sec)</span><br><span class="line">Rows matched: 1  Changed: 1  Warnings: 0</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 问题3：SESSION1 为 mylock 表加了写锁，不能读其他表!</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SELECT * FROM `book`;</span></span><br><span class="line">ERROR 1100 (HY000): Table &#x27;book&#x27; was not locked with LOCK TABLES</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> SESSION2</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 问题1：SESSION1 为 mylock 表加了写锁，SESSION2 读 mylock 表会阻塞，等待 SESSION1 释放！</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SELECT * FROM `mylock`;</span></span><br><span class="line">^C^C -- query aborted</span><br><span class="line">ERROR 1317 (70100): Query execution was interrupted</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 问题2：SESSION1 为 mylock 表加了写锁，SESSION2 更新 mylock 表会阻塞，等待 SESSION1 释放！</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> UPDATE `mylock` SET `name` = <span class="string">&#x27;abc&#x27;</span> WHERE `id` = 1;</span></span><br><span class="line">^C^C -- query aborted</span><br><span class="line">ERROR 1317 (70100): Query execution was interrupted</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 问题3：SESSION1 为 mylock 表加了写锁，SESSION2 可以读其他表！</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SELECT * FROM `book`;</span></span><br><span class="line">+-----------+-------------+</span><br><span class="line">| bookid   |   card |</span><br><span class="line">+-----------+-------------+</span><br><span class="line">|      1 |    1 |</span><br><span class="line">|      7 |    4 |</span><br><span class="line">|      8 |    4 |</span><br><span class="line">|      9 |    5 |</span><br><span class="line">|      5 |    6 |</span><br><span class="line">|     17 |    6 |</span><br><span class="line">|     15 |    8 |</span><br><span class="line">+--------+------+</span><br><span class="line">24 rows in set (0.00 sec)</span><br></pre></td></tr></table></figure>

<h2 id="16-5-案例结论"><a href="#16-5-案例结论" class="headerlink" title="16.5.案例结论"></a>16.5.案例结论</h2><p><strong><code>MyISAM</code>引擎在执行查询语句<code>SELECT</code>之前，会自动给涉及到的所有表加读锁，在执行增删改之前，会自动给涉及的表加写锁。</strong></p>
<p>MySQL 的表级锁有两种模式：</p>
<ul>
<li><p>表共享读锁（Table Read Lock）。</p>
</li>
<li><p>表独占写锁（Table Write Lock）。</p>
</li>
</ul>
<p>対<code>MyISAM</code>表进行操作，会有以下情况：</p>
<ul>
<li>対<code>MyISAM</code>表的读操作（加读锁），不会阻塞其他线程対同一表的读操作，但是会阻塞其他线程対同一表的写操作。只有当读锁释放之后，才会执行其他线程的写操作。</li>
<li>対<code>MyISAM</code>表的写操作（加写锁），会阻塞其他线程対同一表的读和写操作，只有当写锁释放之后，才会执行其他线程的读写操作。</li>
</ul>
<h2 id="16-6-表锁分析"><a href="#16-6-表锁分析" class="headerlink" title="16.6.表锁分析"></a>16.6.表锁分析</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SHOW STATUS LIKE <span class="string">&#x27;table%&#x27;</span>;</span></span><br><span class="line">+----------------------------+-------+</span><br><span class="line">| Variable_name         | Value |</span><br><span class="line">+----------------------------+-------+</span><br><span class="line">| Table_locks_immediate    | 173   |</span><br><span class="line">| Table_locks_waited      | 0     |</span><br><span class="line">| Table_open_cache_hits    | 5     |</span><br><span class="line">| Table_open_cache_misses   | 8    |</span><br><span class="line">| Table_open_cache_overflows | 0    |</span><br><span class="line">+----------------------------+-------+</span><br><span class="line">5 rows in set (0.00 sec)</span><br></pre></td></tr></table></figure>

<p>可以通过<code>Table_locks_immediate</code>和<code>Table_locks_waited</code>状态变量来分析系统上的表锁定。具体说明如下：</p>
<p><code>Table_locks_immediate</code>：产生表级锁定的次数，表示可以立即获取锁的查询次数，每立即获取锁值加 1。</p>
<p><code>Table_locks_waited</code>：出现表级锁定争用而发生等待的次数（不能立即获取锁的次数，每等待一次锁值加 1），此值高则说明存在较严重的表级锁争用情况。</p>
<p><strong>此外，<code>MyISAM</code>的读写锁调度是写优先，这也是<code>MyISAM</code>不适合作为主表的引擎。因为写锁后，其他线程不能进行任何操作，大量的写操作会使查询很难得到锁，从而造成永远阻塞。</strong></p>
<h1 id="17-行锁-偏写"><a href="#17-行锁-偏写" class="headerlink" title="17.行锁(偏写)"></a>17.行锁(偏写)</h1><p><strong>行锁特点：</strong></p>
<ul>
<li>偏向<code>InnoDB</code>存储引擎，开销大，加锁慢；会出现死锁；锁定粒度最小，发生锁冲突的概率最低，并发度最高。</li>
</ul>
<p><strong><code>InnoDB</code>存储引擎和<code>MyISAM</code>存储引擎最大不同有两点：一是支持事务，二是采用行锁。</strong></p>
<p>事务的 ACID：</p>
<ul>
<li><code>Atomicity [ˌætəˈmɪsəti] </code> 原子性。</li>
<li><code>Consistency [kənˈsɪstənsi] </code> 一致性。</li>
<li><code>Isolation [ˌaɪsəˈleɪʃn]</code> 隔离性。</li>
<li><code>Durability [ˌdjʊərəˈbɪlɪti] </code>持久性。</li>
</ul>
<p><strong>原子性</strong>：一个事务必须被视为一个不可分割的最小单位，要不全部提交成功，要么全部失败回滚。<br><strong>一致性</strong>：数据库总是从一个一致性的状态转换到另外一个一致性状态，不会出现部分数据状态改变了部分状态没有改变的情况。<br><strong>隔离性</strong>：通常来说，一个事务所做的修改在最终提交之前，对其他事务是不可见的。这个和数据库的隔离级别有关，所以只能通常来说。<br><strong>持久性</strong>：一旦事务提交，则其所做的修改会被永久保存到数据库中。</p>
<h2 id="17-1-环境准备"><a href="#17-1-环境准备" class="headerlink" title="17.1.环境准备"></a>17.1.环境准备</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"># 建表语句</span><br><span class="line">CREATE TABLE &#96;test_innodb_lock&#96;(</span><br><span class="line">&#96;a&#96; INT,</span><br><span class="line">&#96;b&#96; VARCHAR(16)</span><br><span class="line">)ENGINE&#x3D;INNODB DEFAULT CHARSET&#x3D;utf8 COMMENT&#x3D;&#39;测试行锁&#39;; </span><br><span class="line"></span><br><span class="line"># 插入数据</span><br><span class="line">INSERT INTO &#96;test_innodb_lock&#96;(&#96;a&#96;, &#96;b&#96;) VALUES(1, &#39;b2&#39;);</span><br><span class="line">INSERT INTO &#96;test_innodb_lock&#96;(&#96;a&#96;, &#96;b&#96;) VALUES(2, &#39;3&#39;);</span><br><span class="line">INSERT INTO &#96;test_innodb_lock&#96;(&#96;a&#96;, &#96;b&#96;) VALUES(3, &#39;4000&#39;);</span><br><span class="line">INSERT INTO &#96;test_innodb_lock&#96;(&#96;a&#96;, &#96;b&#96;) VALUES(4, &#39;5000&#39;);</span><br><span class="line">INSERT INTO &#96;test_innodb_lock&#96;(&#96;a&#96;, &#96;b&#96;) VALUES(5, &#39;6000&#39;);</span><br><span class="line">INSERT INTO &#96;test_innodb_lock&#96;(&#96;a&#96;, &#96;b&#96;) VALUES(6, &#39;7000&#39;);</span><br><span class="line">INSERT INTO &#96;test_innodb_lock&#96;(&#96;a&#96;, &#96;b&#96;) VALUES(7, &#39;8000&#39;);</span><br><span class="line">INSERT INTO &#96;test_innodb_lock&#96;(&#96;a&#96;, &#96;b&#96;) VALUES(8, &#39;9000&#39;);</span><br><span class="line"></span><br><span class="line"># 创建索引</span><br><span class="line">CREATE INDEX idx_test_a ON &#96;test_innodb_lock&#96;(a);</span><br><span class="line">CREATE INDEX idx_test_b ON &#96;test_innodb_lock&#96;(b);</span><br></pre></td></tr></table></figure>

<h2 id="17-2-行锁案例"><a href="#17-2-行锁案例" class="headerlink" title="17.2.行锁案例"></a>17.2.行锁案例</h2><blockquote>
<p>1、开启手动提交</p>
</blockquote>
<p>打开<code>SESSION1</code>和<code>SESSION2</code>两个会话，都开启手动提交。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 开启 MySQL 数据库的手动提交</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SET autocommit=0;</span></span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、读几知所写</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> SESSION1</span> </span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> SESSION1 対 test_innodb_lock 表做写操作，但是没有 commit。</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 执行修改 SQL 之后，查询一下 test_innodb_lock 表，发现数据被修改了。</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> UPDATE `test_innodb_lock` SET `b` = <span class="string">&#x27;88&#x27;</span> WHERE `a` = 1;</span></span><br><span class="line">Query OK, 1 row affected (0.00 sec)</span><br><span class="line">Rows matched: 1  Changed: 1  Warnings: 0</span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SELECT * FROM `test_innodb_lock`;</span></span><br><span class="line">+------+----------+</span><br><span class="line">| a    | b     |</span><br><span class="line">+------+----------+</span><br><span class="line">|    1 | 88    |</span><br><span class="line">|    2 | 3     |</span><br><span class="line">|    3 | 4000  |</span><br><span class="line">|    4 | 5000  |</span><br><span class="line">|    5 | 6000  |</span><br><span class="line">|    6 | 7000  |</span><br><span class="line">|    7 | 8000  |</span><br><span class="line">|    8 | 9000  |</span><br><span class="line">+------+-------+</span><br><span class="line">8 rows in set (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> SESSION2</span> </span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> SESSION2 这时候来查询 test_innodb_lock 表。</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 发现 SESSION2 是读不到 SESSION1 未提交的数据的。</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SELECT * FROM `test_innodb_lock`;</span></span><br><span class="line">+------+-------+</span><br><span class="line">| a    | b     |</span><br><span class="line">+------+-------+</span><br><span class="line">|    1 | b2    |</span><br><span class="line">|    2 | 3     |</span><br><span class="line">|    3 | 4000  |</span><br><span class="line">|    4 | 5000  |</span><br><span class="line">|    5 | 6000  |</span><br><span class="line">|    6 | 7000  |</span><br><span class="line">|    7 | 8000  |</span><br><span class="line">|    8 | 9000  |</span><br><span class="line">+------+-------+</span><br><span class="line">8 rows in set (0.00 se</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、行锁两个 SESSION 同时対一条记录进行写操作</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> SESSION1 対 test_innodb_lock 表的`a`=1 这一行进行写操作，但是没有 commit</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> UPDATE `test_innodb_lock` SET `b` = <span class="string">&#x27;99&#x27;</span> WHERE `a` = 1;</span></span><br><span class="line">Query OK, 1 row affected (0.00 sec)</span><br><span class="line">Rows matched: 1  Changed: 1  Warnings: 0</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> SESSION2 也对 test_innodb_lock 表的`a`=1 这一行进行写操作，但是发现阻塞了！！！</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 等SESSION1 执行 commit 语句之后，SESSION2 的 SQL 就会执行了</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> UPDATE `test_innodb_lock` SET `b` = <span class="string">&#x27;asdasd&#x27;</span> WHERE `a` = 1;</span></span><br><span class="line">ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、行锁两个 SESSION 同时对不同记录进行写操作</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> SESSION1 対 test_innodb_lock 表的`a`=6 这一行进行写操作，但是没有 commit</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> UPDATE `test_innodb_lock` SET `b` = <span class="string">&#x27;8976&#x27;</span> WHERE `a` = 6;</span></span><br><span class="line">Query OK, 1 row affected (0.00 sec)</span><br><span class="line">Rows matched: 1  Changed: 1  Warnings: 0</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> SESSION2 対 test_innodb_lock 表的`a`=4 这一行进行写操作，没有阻塞！！！</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> SESSION1 和 SESSION2 同时对不同的行进行写操作互不影响</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> UPDATE `test_innodb_lock` SET `b` = <span class="string">&#x27;Ringo&#x27;</span> WHERE `a` = 4;</span></span><br><span class="line">Query OK, 1 row affected (0.00 sec)</span><br><span class="line">Rows matched: 1  Changed: 1  Warnings: 0</span><br></pre></td></tr></table></figure>

<h2 id="17-3-索引失效行锁变表锁"><a href="#17-3-索引失效行锁变表锁" class="headerlink" title="17.3.索引失效行锁变表锁"></a>17.3.索引失效行锁变表锁</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> SESSION1 执行 SQL 语句，没有执行 commit。</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 由于`b`字段是字符串，但是没有加单引号导致索引失效</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> UPDATE `test_innodb_lock` SET `a` = 888 WHERE `b` = 8000;</span></span><br><span class="line">Query OK, 1 row affected, 1 warning (0.00 sec)</span><br><span class="line">Rows matched: 1  Changed: 1  Warnings: 1</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> SESSION2 和 SESSION1 操作的并不是同一行，但是也被阻塞了？？？</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 由于 SESSION1 执行的 SQL 索引失效，导致行锁升级为表锁。</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> UPDATE `test_innodb_lock` SET `b` = <span class="string">&#x27;1314&#x27;</span> WHERE `a` = 1;</span></span><br><span class="line">ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction</span><br></pre></td></tr></table></figure>

<h2 id="17-4-间隙锁的危害"><a href="#17-4-间隙锁的危害" class="headerlink" title="17.4.间隙锁的危害"></a>17.4.间隙锁的危害</h2><blockquote>
<p>什么是间隙锁？</p>
</blockquote>
<p>当我们用范围条件而不是相等条件检索数据，并请求共享或者排他锁时，<code>InnoDB</code>会给符合条件的已有数据记录的索引项加锁，对于键值在条件范文内但并不存在的记录，叫做”间隙(GAP)”。</p>
<p><code>InnoDB</code>也会对这个”间隙”加锁，这种锁的机制就是所谓的”间隙锁”。</p>
<blockquote>
<p>间隙锁的危害</p>
</blockquote>
<p>因为<code>Query</code>执行过程中通过范围查找的话，他<strong>会锁定整个范围内所有的索引键值，即使这个键值不存在</strong>。</p>
<p>间隙锁有一个比较致命的缺点，就是<strong>当锁定一个范围的键值后，即使某些不存在的键值也会被无辜的锁定，而造成在锁定的时候无法插入锁定键值范围内的任何数据。</strong>在某些场景下这可能会対性能造成很大的危害。</p>
<h2 id="17-5-如何锁定一行"><a href="#17-5-如何锁定一行" class="headerlink" title="17.5.如何锁定一行"></a>17.5.如何锁定一行</h2><p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/2020080616050355.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JyaW5nb18=,size_16,color_FFFFFF,t_70" alt="锁定一行"></p>
<p><code>SELECT .....FOR UPDATE</code>在锁定某一行后，其他写操作会被阻塞，直到锁定的行被<code>COMMIT</code>。</p>
<h2 id="17-6-案例结论"><a href="#17-6-案例结论" class="headerlink" title="17.6.案例结论"></a>17.6.案例结论</h2><p><code>InnoDB</code>存储引擎由于实现了行级锁定，虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更高一些，但是在整体并发处理能力方面要远远优于<code>MyISAM</code>的表级锁定的。当系统并发量较高的时候，<code>InnoDB</code>的整体性能和<code>MyISAM</code>相比就会有比较明显的优势了。</p>
<p>但是，<code>InnoDB</code>的行级锁定同样也有其脆弱的一面，当我们使用不当的时候，可能会让<code>InnoDB</code>的整体性能表现不仅不能比<code>MyISAM</code>高，甚至可能会更差。</p>
<h2 id="17-7-行锁分析"><a href="#17-7-行锁分析" class="headerlink" title="17.7.行锁分析"></a>17.7.行锁分析</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SHOW STATUS LIKE <span class="string">&#x27;innodb_row_lock%&#x27;</span>;</span></span><br><span class="line">+-------------------------------+--------+</span><br><span class="line">| Variable_name            | Value  |</span><br><span class="line">+-------------------------------+--------+</span><br><span class="line">| Innodb_row_lock_current_waits | 0    |</span><br><span class="line">| Innodb_row_lock_time       | 124150 |</span><br><span class="line">| Innodb_row_lock_time_avg    | 31037  |</span><br><span class="line">| Innodb_row_lock_time_max    | 51004  |</span><br><span class="line">| Innodb_row_lock_waits      | 4    |</span><br><span class="line">+-------------------------------+--------+</span><br><span class="line">5 rows in set (0.00 sec)</span><br></pre></td></tr></table></figure>

<p>対各个状态量的说明如下：</p>
<ul>
<li><code>Innodb_row_lock_current_waits</code>：当前正在等待锁定的数量。</li>
<li><code>Innodb_row_lock_time</code>：从系统启动到现在锁定总时间长度（重要）。</li>
<li><code>Innodb_row_lock_time_avg</code>：每次等待所花的平均时间（重要）。</li>
<li><code>Innodb_row_lock_time_max</code>：从系统启动到现在等待最长的一次所花的时间。</li>
<li><code>Innodb_row_lock_waits</code>：系统启动后到现在总共等待的次数（重要）。</li>
</ul>
<p>尤其是当等待次数很高，而且每次等待时长也不小的时候，我们就需要分析系统中为什么会有如此多的等待，然后根据分析结果着手制定优化策略。</p>
<h1 id="18-主从复制"><a href="#18-主从复制" class="headerlink" title="18.主从复制"></a>18.主从复制</h1><h2 id="18-1-复制基本原理"><a href="#18-1-复制基本原理" class="headerlink" title="18.1.复制基本原理"></a>18.1.复制基本原理</h2><p><img src= "/img/loading.gif" data-lazy-src="https://img-blog.csdnimg.cn/20200806170415401.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JyaW5nb18=,size_16,color_FFFFFF,t_70" alt="主从复制"></p>
<p>MySQL 复制过程分为三步：</p>
<ul>
<li>Master 将改变记录到二进制日志 (Binary Log)。这些记录过程叫做二进制日志事件，<code>Binary Log Events</code>；</li>
<li>Slave 将 Master 的<code>Binary Log Events</code>拷贝到它的中继日志 (Replay  Log);</li>
<li>Slave 重做中继日志中的事件，将改变应用到自己的数据库中。MySQL 复制是异步且串行化的。</li>
</ul>
<h2 id="18-2-复制基本原则"><a href="#18-2-复制基本原则" class="headerlink" title="18.2.复制基本原则"></a>18.2.复制基本原则</h2><ul>
<li>每个 Slave 只有一个 Master。</li>
<li>每个 Slave 只能有一个唯一的服务器ID。</li>
<li>每个 Master 可以有多个 Salve。</li>
</ul>
<h2 id="18-3-一主一从配置"><a href="#18-3-一主一从配置" class="headerlink" title="18.3.一主一从配置"></a>18.3.一主一从配置</h2><blockquote>
<p>1、基本要求：Master 和 Slave 的 MySQL <strong>服务器版本一致</strong>且后台以服务运行。</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 创建 mysql-slave1 实例</span></span><br><span class="line">docker run -p 3307:3306 --name mysql-slave1 \</span><br><span class="line">-v /root/mysql-slave1/log:/var/log/mysql \</span><br><span class="line">-v /root/mysql-slave1/data:/var/lib/mysql \</span><br><span class="line">-v /root/mysql-slave1/conf:/etc/mysql \</span><br><span class="line">-e MYSQL_ROOT_PASSWORD=333 \</span><br><span class="line">-d mysql:5.7</span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、主从配置都是配在 [mysqld] 节点下，都是小写</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> Master 配置</span></span><br><span class="line">[mysqld]</span><br><span class="line">server-id=1 # 必须</span><br><span class="line">log-bin=/var/lib/mysql/mysql-bin # 必须</span><br><span class="line">read-only=0</span><br><span class="line">binlog-ignore-db=mysql</span><br></pre></td></tr></table></figure>

<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> Slave 配置</span></span><br><span class="line">[mysqld]</span><br><span class="line">server-id=2 # 必须</span><br><span class="line">log-bin=/var/lib/mysql/mysql-bin</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、Master 配置</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1、GRANT REPLICATION SLAVE ON *.* TO <span class="string">&#x27;username&#x27;</span>@<span class="string">&#x27;从机IP地址&#x27;</span> IDENTIFIED BY <span class="string">&#x27;password&#x27;</span>;</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> GRANT REPLICATION SLAVE ON *.* TO <span class="string">&#x27;zhangsan&#x27;</span>@<span class="string">&#x27;172.18.0.3&#x27;</span> IDENTIFIED BY <span class="string">&#x27;123456&#x27;</span>;</span></span><br><span class="line">Query OK, 0 rows affected, 1 warning (0.01 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 2、刷新命令</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> FLUSH PRIVILEGES;</span></span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 3、记录下 File 和 Position</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 每次配从机的时候都要 SHOW MASTER STATUS;查看最新的 File和 Position</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SHOW MASTER STATUS;</span></span><br><span class="line">+------------------+----------+--------------+------------------+-------------------+</span><br><span class="line">| File         | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |</span><br><span class="line">+------------------+----------+--------------+------------------+-------------------+</span><br><span class="line">| mysql-bin.000001 |    602 |          | mysql        |             |</span><br><span class="line">+------------------+----------+--------------+------------------+-------------------+</span><br><span class="line">1 row in set (0.00 sec)</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、Slave 从机配置</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">CHANGE MASTER TO MASTER_HOST=&#x27;172.18.0.4&#x27;,</span><br><span class="line">MASTER_USER=&#x27;zhangsan&#x27;,</span><br><span class="line">MASTER_PASSWORD=&#x27;123456&#x27;,</span><br><span class="line">MASTER_LOG_FILE=&#x27;mysql-bin.File的编号&#x27;,</span><br><span class="line">MASTER_LOG_POS=Position的最新值;</span><br></pre></td></tr></table></figure>



<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1、使用用户名密码登录进 Master</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> CHANGE MASTER TO MASTER_HOST=<span class="string">&#x27;172.18.0.4&#x27;</span>,</span></span><br><span class="line">    -&gt; MASTER_USER=&#x27;zhangsan&#x27;,</span><br><span class="line">    -&gt; MASTER_PASSWORD=&#x27;123456&#x27;,</span><br><span class="line">    -&gt; MASTER_LOG_FILE=&#x27;mysql-bin.000001&#x27;,</span><br><span class="line">    -&gt; MASTER_LOG_POS=602;</span><br><span class="line">Query OK, 0 rows affected, 2 warnings (0.02 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 2、开启 Slave 从机的复制</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> START SLAVE;</span></span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 3、查看 Slave 状态</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> Slave_IO_Running 和 Slave_SQL_Running 必须同时为 Yes 说明主从复制配置成功！</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SHOW SLAVE STATUS\G</span></span><br><span class="line">*************************** 1. row ***************************</span><br><span class="line">Slave_IO_State: Waiting for master to send event # Slave待命状态</span><br><span class="line">Master_Host: 172.18.0.4</span><br><span class="line">Master_User: zhangsan</span><br><span class="line">Master_Port: 3306</span><br><span class="line">Connect_Retry: 60</span><br><span class="line">Master_Log_File: mysql-bin.000001</span><br><span class="line">Read_Master_Log_Pos: 602</span><br><span class="line">Relay_Log_File: b030ad25d5fe-relay-bin.000002</span><br><span class="line">Relay_Log_Pos: 320</span><br><span class="line">Relay_Master_Log_File: mysql-bin.000001</span><br><span class="line">Slave_IO_Running: Yes  </span><br><span class="line">Slave_SQL_Running: Yes</span><br><span class="line">Replicate_Do_DB: </span><br><span class="line">Replicate_Ignore_DB: </span><br><span class="line">Replicate_Do_Table: </span><br><span class="line">Replicate_Ignore_Table: </span><br><span class="line">Replicate_Wild_Do_Table: </span><br><span class="line">Replicate_Wild_Ignore_Table: </span><br><span class="line">Last_Errno: 0</span><br><span class="line">Last_Error: </span><br><span class="line">Skip_Counter: 0</span><br><span class="line">Exec_Master_Log_Pos: 602</span><br><span class="line">Relay_Log_Space: 534</span><br><span class="line">Until_Condition: None</span><br><span class="line">Until_Log_File: </span><br><span class="line">Until_Log_Pos: 0</span><br><span class="line">Master_SSL_Allowed: No</span><br><span class="line">Master_SSL_CA_File: </span><br><span class="line">Master_SSL_CA_Path: </span><br><span class="line">Master_SSL_Cert: </span><br><span class="line">Master_SSL_Cipher: </span><br><span class="line">Master_SSL_Key: </span><br><span class="line">Seconds_Behind_Master: 0</span><br><span class="line">Master_SSL_Verify_Server_Cert: No</span><br><span class="line">Last_IO_Errno: 0</span><br><span class="line">Last_IO_Error: </span><br><span class="line">Last_SQL_Errno: 0</span><br><span class="line">Last_SQL_Error: </span><br><span class="line">Replicate_Ignore_Server_Ids: </span><br><span class="line">Master_Server_Id: 1</span><br><span class="line">Master_UUID: bd047557-b20c-11ea-9961-0242ac120002</span><br><span class="line">Master_Info_File: /var/lib/mysql/master.info</span><br><span class="line">SQL_Delay: 0</span><br><span class="line">SQL_Remaining_Delay: NULL</span><br><span class="line">Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates</span><br><span class="line">Master_Retry_Count: 86400</span><br><span class="line">Master_Bind: </span><br><span class="line">Last_IO_Error_Timestamp: </span><br><span class="line">Last_SQL_Error_Timestamp: </span><br><span class="line">Master_SSL_Crl: </span><br><span class="line">Master_SSL_Crlpath: </span><br><span class="line">Retrieved_Gtid_Set: </span><br><span class="line">Executed_Gtid_Set: </span><br><span class="line">Auto_Position: 0</span><br><span class="line">Replicate_Rewrite_DB: </span><br><span class="line">Channel_Name: </span><br><span class="line">Master_TLS_Version: </span><br><span class="line">1 row in set (0.00 sec)</span><br></pre></td></tr></table></figure>

<blockquote>
<p>5、测试主从复制</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> Master 创建数据库</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> create database test_replication;</span></span><br><span class="line">Query OK, 1 row affected (0.01 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> Slave 查询数据库</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> show databases;</span></span><br><span class="line">+--------------------+</span><br><span class="line">| Database           |</span><br><span class="line">+--------------------+</span><br><span class="line">| information_schema |</span><br><span class="line">| mysql              |</span><br><span class="line">| performance_schema |</span><br><span class="line">| sys                |</span><br><span class="line">| test_replication   |</span><br><span class="line">+--------------------+</span><br><span class="line">5 rows in set (0.00 sec)</span><br></pre></td></tr></table></figure>

<blockquote>
<p>6、停止主从复制功能</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1、停止 Slave</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> STOP SLAVE;</span></span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 2、重新配置主从</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> MASTER_LOG_FILE 和 MASTER_LOG_POS 一定要根据最新的数据来配</span></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> CHANGE MASTER TO MASTER_HOST=<span class="string">&#x27;172.18.0.4&#x27;</span>,</span></span><br><span class="line">    -&gt; MASTER_USER=&#x27;zhangsan&#x27;,</span><br><span class="line">    -&gt; MASTER_PASSWORD=&#x27;123456&#x27;,</span><br><span class="line">    -&gt; MASTER_LOG_FILE=&#x27;mysql-bin.000001&#x27;,</span><br><span class="line">    -&gt; MASTER_LOG_POS=797;</span><br><span class="line">Query OK, 0 rows affected, 2 warnings (0.01 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> START SLAVE;</span></span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br><span class="line"></span><br><span class="line"><span class="meta">mysql&gt;</span><span class="bash"> SHOW SLAVE STATUS\G</span></span><br><span class="line">*************************** 1. row ***************************</span><br><span class="line">Slave_IO_State: Waiting for master to send event</span><br><span class="line">Master_Host: 172.18.0.4</span><br><span class="line">Master_User: zhangsan</span><br><span class="line">Master_Port: 3306</span><br><span class="line">Connect_Retry: 60</span><br><span class="line">Master_Log_File: mysql-bin.000001</span><br><span class="line">Read_Master_Log_Pos: 797</span><br><span class="line">Relay_Log_File: b030ad25d5fe-relay-bin.000002</span><br><span class="line">Relay_Log_Pos: 320</span><br><span class="line">Relay_Master_Log_File: mysql-bin.000001</span><br><span class="line">Slave_IO_Running: Yes</span><br><span class="line">Slave_SQL_Running: Yes</span><br><span class="line">Replicate_Do_DB: </span><br><span class="line">Replicate_Ignore_DB: </span><br><span class="line">Replicate_Do_Table: </span><br><span class="line">Replicate_Ignore_Table: </span><br><span class="line">Replicate_Wild_Do_Table: </span><br><span class="line">Replicate_Wild_Ignore_Table: </span><br><span class="line">Last_Errno: 0</span><br><span class="line">Last_Error: </span><br><span class="line">Skip_Counter: 0</span><br><span class="line">Exec_Master_Log_Pos: 797</span><br><span class="line">Relay_Log_Space: 534</span><br><span class="line">Until_Condition: None</span><br><span class="line">Until_Log_File: </span><br><span class="line">Until_Log_Pos: 0</span><br><span class="line">Master_SSL_Allowed: No</span><br><span class="line">Master_SSL_CA_File: </span><br><span class="line">Master_SSL_CA_Path: </span><br><span class="line">Master_SSL_Cert: </span><br><span class="line">Master_SSL_Cipher: </span><br><span class="line">Master_SSL_Key: </span><br><span class="line">Seconds_Behind_Master: 0</span><br><span class="line">Master_SSL_Verify_Server_Cert: No</span><br><span class="line">Last_IO_Errno: 0</span><br><span class="line">Last_IO_Error: </span><br><span class="line">Last_SQL_Errno: 0</span><br><span class="line">Last_SQL_Error: </span><br><span class="line">Replicate_Ignore_Server_Ids: </span><br><span class="line">Master_Server_Id: 1</span><br><span class="line">Master_UUID: bd047557-b20c-11ea-9961-0242ac120002</span><br><span class="line">Master_Info_File: /var/lib/mysql/master.info</span><br><span class="line">SQL_Delay: 0</span><br><span class="line">SQL_Remaining_Delay: NULL</span><br><span class="line">Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates</span><br><span class="line">Master_Retry_Count: 86400</span><br><span class="line">Master_Bind: </span><br><span class="line">Last_IO_Error_Timestamp: </span><br><span class="line">Last_SQL_Error_Timestamp: </span><br><span class="line">Master_SSL_Crl: </span><br><span class="line">Master_SSL_Crlpath: </span><br><span class="line">Retrieved_Gtid_Set: </span><br><span class="line">Executed_Gtid_Set: </span><br><span class="line">Auto_Position: 0</span><br><span class="line">Replicate_Rewrite_DB: </span><br><span class="line">Channel_Name: </span><br><span class="line">Master_TLS_Version: </span><br><span class="line">1 row in set (0.00 sec)</span><br></pre></td></tr></table></figure>

<h3 id="18-4-主从复制-索引"><a href="#18-4-主从复制-索引" class="headerlink" title="18.4 主从复制 索引"></a>18.4 主从复制 索引</h3><p>主表作为写表</p>
<p>从表作为读表，在从表上建立索引</p>
<h1 id="MySQL-主从同步的原理"><a href="#MySQL-主从同步的原理" class="headerlink" title="MySQL 主从同步的原理"></a>MySQL 主从同步的原理</h1><h2 id="一、异步复制原理"><a href="#一、异步复制原理" class="headerlink" title="一、异步复制原理"></a>一、异步复制原理</h2><h3 id="1、主从同步的简介"><a href="#1、主从同步的简介" class="headerlink" title="1、主从同步的简介"></a>1、主从同步的简介</h3><p>MySQL 主从复制就是将一个 mysql 实例（Master）中的数据实时复制到另一个 MySQL 实例 (slave) 中，而且这个复制是一个异步复制的过程。</p>
<p>实现整个复制操作主要由三个进程完成的，其中两个进程在 Slave（sql_thread 和 IO_thread），另外一个进程在 Master（IO 进程）上。</p>
<h3 id="2、主从同步的原理图"><a href="#2、主从同步的原理图" class="headerlink" title="2、主从同步的原理图"></a>2、主从同步的原理图</h3><p><img src= "/img/loading.gif" data-lazy-src="https://gitee.com/forkiller/picture/raw/master/img/20210902162441.png" alt="主从同步原理"></p>
<h3 id="3、主从同步的流程"><a href="#3、主从同步的流程" class="headerlink" title="3、主从同步的流程"></a>3、主从同步的流程</h3><p> mysql 实例（Master）必须开启 bin-log 日志功能，否则无法实现。因为主从同步的本质是：<strong>从服务器（slave）获取主机 Master 的 二进制日志（Binary log），之后按顺序执行日志上的各种操作。</strong></p>
<p>详细流程如下：</p>
<p>1）增删改事务提交给 Master 后，Master 会开启 IO_thread，将增删改操作写入 Binary log 日志中；</p>
<p>2）从机通过 start slave 开启本机的 IO_thread，IO_thread 会先读取本机上次同步的位置（postion）；</p>
<p>3）从机的 IO_thread 会连接上 Master，并请求在指定日志文件(Binary log) 的指定位置（从机中的 postion）之后的日志内容；</p>
<p>4）Master 接收到从机的 IO_thread 请求后，通过本机负责复制的 IO 线程根据请求信息读取指定日志指定位置之后的日志信息，返回给从机的 IO_thread，返回信息中除了日志所包含的信息之外，还包括本次返回的信息已经到 Master 端的 Binary log file 的以及 bin-log postion；</p>
<p>5）从机的 IO thread 接收到的信息，写入从机的 Replay log 日志最末端中；并将读取到的 Master 端的 Binary log 的文件名和位置记录到 master-info 文件中，以便在下一次读取的时候能够清楚的告诉 Master “我需要从某个 Binary log 的哪 个位置开始往后的日志内容，请发给我”；</p>
<p>6）Slave 的 Sql_thread 检测到 Replay-log 中新增加了内容后，会马上解析 Replay-log 的内容成为在 Master 端真实执行时候的那些可执行的内容，并在本数据库中执行。</p>
<p>详细流程图如下：</p>
<p><img src= "/img/loading.gif" data-lazy-src="https://gitee.com/forkiller/picture/raw/master/img/20210902162601.png" alt="image-20210902162600081"></p>
<h2 id="二、半同步原理"><a href="#二、半同步原理" class="headerlink" title="二、半同步原理"></a>二、半同步原理</h2><h3 id="1、半同步流程"><a href="#1、半同步流程" class="headerlink" title="1、半同步流程"></a>1、半同步流程</h3><p>半同步是在事务提交前，主服务器的守护进程就会通知从从服务：主服务机的数据发生发生变化（实际数据还未真实写入主服务器的磁盘，事务提交后才写入），此时从服务器会先去上次同步的 postion，再去主服务器读取主机的 postion ，之后再写入master-info 和 Relay-log，sql_thread 读取 Relay-log 的信息，执行 sql 语句。</p>
<p>半同步过程中，用户请求提交后，会一直等待。因为主服务会等待所有从服务器完成同步操作，最后主服务器才给请求一个响应。</p>
<p>为解决用户请求一直等待的问题，半同步中会设置一个超时时间，默认 timeout=10 秒。当从机宕机或同步耗时超过timout 时间，则主从间的半同步会变为异步复制，主机只会记录改从机的同步状态（哪台从机上次同步失败了）；只有当该从机重启正常后，主从间才会变回原来的半同步。</p>
<h3 id="2、半同步应用场景"><a href="#2、半同步应用场景" class="headerlink" title="2、半同步应用场景"></a>2、半同步应用场景</h3><p>根据半同步的流程可知，用户的请求会等待一定时间才能得到主服务器的响应，这样影响了用户体验，但是却保证了主服务器和从服务器间的数据一致，故半同步主要应用在要求数据安全性高的情况，如金额、数字校验等。</p>
<h2 id="三、异步复制和半同步区别"><a href="#三、异步复制和半同步区别" class="headerlink" title="三、异步复制和半同步区别"></a>三、异步复制和半同步区别</h2><table>
<thead>
<tr>
<th></th>
<th>异步复制</th>
<th>半同步</th>
</tr>
</thead>
<tbody><tr>
<td>守护线程通知</td>
<td>在事务提交后</td>
<td>在事务提交前</td>
</tr>
<tr>
<td>主机是否等待从机同步</td>
<td>否</td>
<td>是</td>
</tr>
<tr>
<td>超时时间timeout</td>
<td>无</td>
<td>默认 10 秒</td>
</tr>
<tr>
<td>从机宕机</td>
<td>主机仅记录从机的同步状态</td>
<td>从机会变为异步复制，<br />从机重启正常后变回半同步</td>
</tr>
<tr>
<td>数据一致性</td>
<td>弱</td>
<td>强</td>
</tr>
</tbody></table>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">Steve</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://steve6636.gitee.io/2021/10/24/MySQL_%E5%91%A8%E9%98%B3%202018%20%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0_20210405/">https://steve6636.gitee.io/2021/10/24/MySQL_%E5%91%A8%E9%98%B3%202018%20%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0_20210405/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://steve6636.gitee.io" target="_blank">小波的博客</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"></div><div class="post_share"><div class="social-share" data-image="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/social-share.js/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/social-share.js/dist/js/social-share.min.js" defer></script></div></div><div class="post-reward"><div class="reward-button button--animated"><i class="fas fa-qrcode"></i> 打赏</div><div class="reward-main"><ul class="reward-all"><li class="reward-item"><a href="/img/wechat.jpg" target="_blank"><img class="post-qr-code-img" data-lazy-src="/img/wechat.jpg" alt="wechat"/></a><div class="post-qr-code-desc">wechat</div></li><li class="reward-item"><a href="/img/alipay.jpg" target="_blank"><img class="post-qr-code-img" data-lazy-src="/img/alipay.jpg" alt="alipay"/></a><div class="post-qr-code-desc">alipay</div></li></ul></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/2022/03/06/Docker%20%E7%AC%94%E8%AE%B0_20210404/"><img class="prev-cover" data-lazy-src="https://gitee.com/forkiller/picture/raw/master/img/20220306223850.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">Docker 笔记.md</div></div></a></div><div class="next-post pull-right"><a href="/2021/10/02/MySQL%E4%BA%8B%E5%8A%A1ACID%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86/"><img class="next-cover" data-lazy-src="https://gitee.com/forkiller/picture/raw/master/img/20210930083746.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">“MySQL事务ACID实现原理”</div></div></a></div></nav></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="card-info-avatar is-center"><img class="avatar-img" data-lazy-src="https://gitee.com/forkiller/picture/raw/master/img/20210327175316.png" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/><div class="author-info__name">Steve</div><div class="author-info__description">路漫漫其修远兮，吾将上下而求索</div></div><div class="card-info-data"><div class="card-info-data-item is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">26</div></a></div><div class="card-info-data-item is-center"><a href="/tags/"><div class="headline">标签</div><div class="length-num">11</div></a></div><div class="card-info-data-item is-center"><a href="/categories/"><div class="headline">分类</div><div class="length-num">9</div></a></div></div><a class="button--animated" id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/forkiller"><i class="fab fa-github"></i><span>Follow Me</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/forkiller" target="_blank" title="Github"><i class="fab fa-github"></i></a><a class="social-icon" href="mailto:1518109600@qq.com" target="_blank" title="Email"><i class="fas fa-envelope"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn card-announcement-animation"></i><span>公告</span></div><div class="announcement_content">冷灯看剑，剑上几番功名？炉香无须计苍生，纵一川烟逝，万丈云埋，孤阳还照古陵</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#1-MySQL-%E7%8E%AF%E5%A2%83"><span class="toc-text">1.MySQL 环境</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-1-%E7%8E%AF%E5%A2%83%E5%AE%89%E8%A3%85"><span class="toc-text">1.1.环境安装</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-2-%E5%AE%89%E8%A3%85%E4%BD%8D%E7%BD%AE"><span class="toc-text">1.2.安装位置</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-3-%E4%BF%AE%E6%94%B9%E5%AD%97%E7%AC%A6%E9%9B%86"><span class="toc-text">1.3.修改字符集</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-4-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"><span class="toc-text">1.4.配置文件</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#2-MySQL-%E9%80%BB%E8%BE%91%E6%9E%B6%E6%9E%84"><span class="toc-text">2.MySQL 逻辑架构</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-%E5%AD%98%E5%82%A8%E5%BC%95%E6%93%8E"><span class="toc-text">3.存储引擎</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#4-SQL-%E6%80%A7%E8%83%BD%E4%B8%8B%E9%99%8D%E7%9A%84%E5%8E%9F%E5%9B%A0"><span class="toc-text">4.SQL 性能下降的原因</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#5-SQL-%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F"><span class="toc-text">5.SQL 执行顺序</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#6-%E4%B8%83%E7%A7%8D-JOIN-%E7%90%86%E8%AE%BA"><span class="toc-text">6.七种 JOIN 理论</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#7-%E7%B4%A2%E5%BC%95"><span class="toc-text">7.索引</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#7-1-%E7%B4%A2%E5%BC%95%E7%AE%80%E4%BB%8B"><span class="toc-text">7.1.索引简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-2-MySQL-%E7%B4%A2%E5%BC%95%E5%88%86%E7%B1%BB"><span class="toc-text">7.2.MySQL 索引分类</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%B4%A2%E5%BC%95%E7%9A%84%E5%91%BD%E5%90%8D%E8%A7%84%E8%8C%83"><span class="toc-text">索引的命名规范</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-3-MySQL-%E7%B4%A2%E5%BC%95%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84"><span class="toc-text">7.3.MySQL 索引数据结构</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-4-%E5%93%AA%E4%BA%9B%E6%83%85%E5%86%B5%E9%9C%80%E8%A6%81%E5%BB%BA%E7%B4%A2%E5%BC%95"><span class="toc-text">7.4.哪些情况需要建索引</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-5-%E9%82%A3%E4%BA%9B%E6%83%85%E5%86%B5%E4%B8%8D%E8%A6%81%E5%BB%BA%E7%B4%A2%E5%BC%95"><span class="toc-text">7.5.那些情况不要建索引</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#7-6-%E5%BC%80%E5%90%AF%E5%92%8C%E5%85%B3%E9%97%AD%E7%B4%A2%E5%BC%95"><span class="toc-text">7.6 开启和关闭索引</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#8-%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90"><span class="toc-text">8.性能分析</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#8-1-EXPLAIN-%E7%AE%80%E4%BB%8B"><span class="toc-text">8.1.EXPLAIN 简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8-2-EXPLAIN-%E5%AD%97%E6%AE%B5"><span class="toc-text">8.2.EXPLAIN 字段</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#9-%E7%B4%A2%E5%BC%95%E5%88%86%E6%9E%90"><span class="toc-text">9.索引分析</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#9-1-%E5%8D%95%E8%A1%A8%E7%B4%A2%E5%BC%95%E5%88%86%E6%9E%90"><span class="toc-text">9.1.单表索引分析</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9-2-%E4%B8%A4%E8%A1%A8%E7%B4%A2%E5%BC%95%E5%88%86%E6%9E%90"><span class="toc-text">9.2.两表索引分析</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9-3-%E4%B8%89%E5%BC%A0%E8%A1%A8%E7%B4%A2%E5%BC%95%E5%88%86%E6%9E%90"><span class="toc-text">9.3.三张表索引分析</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9-4-%E7%BB%93%E8%AE%BA"><span class="toc-text">9.4.结论</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#10-%E7%B4%A2%E5%BC%95%E5%A4%B1%E6%95%88"><span class="toc-text">10.索引失效</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#10-1-%E7%B4%A2%E5%BC%95%E5%A4%B1%E6%95%88%E7%9A%84%E6%83%85%E5%86%B5"><span class="toc-text">10.1.索引失效的情况</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10-2-%E6%9C%80%E4%BD%B3%E5%B7%A6%E5%89%8D%E7%BC%80%E6%B3%95%E5%88%99"><span class="toc-text">10.2.最佳左前缀法则</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10-3-%E7%B4%A2%E5%BC%95%E5%88%97%E4%B8%8A%E4%B8%8D%E8%AE%A1%E7%AE%97"><span class="toc-text">10.3.索引列上不计算</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10-4-%E8%8C%83%E5%9B%B4%E4%B9%8B%E5%90%8E%E5%85%A8%E5%A4%B1%E6%95%88"><span class="toc-text">10.4.范围之后全失效</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10-5-%E8%A6%86%E7%9B%96%E7%B4%A2%E5%BC%95%E5%B0%BD%E9%87%8F%E7%94%A8"><span class="toc-text">10.5.覆盖索引尽量用</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10-6-%E4%B8%8D%E7%AD%89%E6%9C%89%E6%97%B6%E4%BC%9A%E5%A4%B1%E6%95%88"><span class="toc-text">10.6.不等有时会失效</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10-7-like-%E7%99%BE%E5%88%86%E5%8A%A0%E5%8F%B3%E8%BE%B9"><span class="toc-text">10.7.like 百分加右边</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10-8-%E5%AD%97%E7%AC%A6%E8%A6%81%E5%8A%A0%E5%8D%95%E5%BC%95%E5%8F%B7"><span class="toc-text">10.8.字符要加单引号</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10-9-%E7%B4%A2%E5%BC%95%E7%9B%B8%E5%85%B3%E9%A2%98%E7%9B%AE"><span class="toc-text">10.9.索引相关题目</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10-10-%E9%9D%A2%E8%AF%95%E9%A2%98%E5%88%86%E6%9E%90"><span class="toc-text">10.10.面试题分析</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10-11-%E6%80%BB%E7%BB%93"><span class="toc-text">10.11.总结</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#11-%E5%88%86%E6%9E%90%E6%85%A2-SQL-%E7%9A%84%E6%AD%A5%E9%AA%A4"><span class="toc-text">11.分析慢 SQL 的步骤</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#12-%E6%9F%A5%E8%AF%A2%E4%BC%98%E5%8C%96"><span class="toc-text">12.查询优化</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#12-1-%E5%B0%8F%E8%A1%A8%E9%A9%B1%E5%8A%A8%E5%A4%A7%E8%A1%A8"><span class="toc-text">12.1.小表驱动大表</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#12-2-ORDER-BY%E4%BC%98%E5%8C%96"><span class="toc-text">12.2.ORDER BY优化</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#12-3-GORUP-BY-%E4%BC%98%E5%8C%96"><span class="toc-text">12.3.GORUP BY 优化</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#12-4-%E6%80%BB%E7%BB%93"><span class="toc-text">12.4.总结</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#13-%E6%85%A2%E6%9F%A5%E8%AF%A2%E6%97%A5%E5%BF%97"><span class="toc-text">13.慢查询日志</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#13-1-%E5%9F%BA%E6%9C%AC%E4%BB%8B%E7%BB%8D"><span class="toc-text">13.1.基本介绍</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#13-2-%E6%97%A5%E5%BF%97%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7"><span class="toc-text">13.2.日志分析工具</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#14-%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%E6%95%B0%E6%8D%AE%E8%84%9A%E6%9C%AC"><span class="toc-text">14.批量插入数据脚本</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#14-1-%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87"><span class="toc-text">14.1.环境准备</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#14-2-%E5%88%9B%E5%BB%BA%E5%87%BD%E6%95%B0"><span class="toc-text">14.2.创建函数</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#14-3-%E5%88%9B%E5%BB%BA%E5%AD%98%E5%82%A8%E8%BF%87%E7%A8%8B"><span class="toc-text">14.3.创建存储过程</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#14-4-%E8%B0%83%E7%94%A8%E5%AD%98%E5%82%A8%E8%BF%87%E7%A8%8B"><span class="toc-text">14.4.调用存储过程</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#15-Show-Profile"><span class="toc-text">15.Show Profile</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#16-%E8%A1%A8%E9%94%81-%E5%81%8F%E8%AF%BB"><span class="toc-text">16.表锁(偏读)</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#16-1-%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87"><span class="toc-text">16.1.环境准备</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#16-2-%E9%94%81%E8%A1%A8%E7%9A%84%E5%91%BD%E4%BB%A4"><span class="toc-text">16.2.锁表的命令</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#16-3-%E8%AF%BB%E9%94%81%E6%A1%88%E4%BE%8B"><span class="toc-text">16.3.读锁案例</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#16-4-%E5%86%99%E9%94%81%E6%A1%88%E4%BE%8B"><span class="toc-text">16.4.写锁案例</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#16-5-%E6%A1%88%E4%BE%8B%E7%BB%93%E8%AE%BA"><span class="toc-text">16.5.案例结论</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#16-6-%E8%A1%A8%E9%94%81%E5%88%86%E6%9E%90"><span class="toc-text">16.6.表锁分析</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#17-%E8%A1%8C%E9%94%81-%E5%81%8F%E5%86%99"><span class="toc-text">17.行锁(偏写)</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#17-1-%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87"><span class="toc-text">17.1.环境准备</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#17-2-%E8%A1%8C%E9%94%81%E6%A1%88%E4%BE%8B"><span class="toc-text">17.2.行锁案例</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#17-3-%E7%B4%A2%E5%BC%95%E5%A4%B1%E6%95%88%E8%A1%8C%E9%94%81%E5%8F%98%E8%A1%A8%E9%94%81"><span class="toc-text">17.3.索引失效行锁变表锁</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#17-4-%E9%97%B4%E9%9A%99%E9%94%81%E7%9A%84%E5%8D%B1%E5%AE%B3"><span class="toc-text">17.4.间隙锁的危害</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#17-5-%E5%A6%82%E4%BD%95%E9%94%81%E5%AE%9A%E4%B8%80%E8%A1%8C"><span class="toc-text">17.5.如何锁定一行</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#17-6-%E6%A1%88%E4%BE%8B%E7%BB%93%E8%AE%BA"><span class="toc-text">17.6.案例结论</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#17-7-%E8%A1%8C%E9%94%81%E5%88%86%E6%9E%90"><span class="toc-text">17.7.行锁分析</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#18-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6"><span class="toc-text">18.主从复制</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#18-1-%E5%A4%8D%E5%88%B6%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86"><span class="toc-text">18.1.复制基本原理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#18-2-%E5%A4%8D%E5%88%B6%E5%9F%BA%E6%9C%AC%E5%8E%9F%E5%88%99"><span class="toc-text">18.2.复制基本原则</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#18-3-%E4%B8%80%E4%B8%BB%E4%B8%80%E4%BB%8E%E9%85%8D%E7%BD%AE"><span class="toc-text">18.3.一主一从配置</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#18-4-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6-%E7%B4%A2%E5%BC%95"><span class="toc-text">18.4 主从复制 索引</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#MySQL-%E4%B8%BB%E4%BB%8E%E5%90%8C%E6%AD%A5%E7%9A%84%E5%8E%9F%E7%90%86"><span class="toc-text">MySQL 主从同步的原理</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%80%E3%80%81%E5%BC%82%E6%AD%A5%E5%A4%8D%E5%88%B6%E5%8E%9F%E7%90%86"><span class="toc-text">一、异步复制原理</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%E3%80%81%E4%B8%BB%E4%BB%8E%E5%90%8C%E6%AD%A5%E7%9A%84%E7%AE%80%E4%BB%8B"><span class="toc-text">1、主从同步的简介</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%E3%80%81%E4%B8%BB%E4%BB%8E%E5%90%8C%E6%AD%A5%E7%9A%84%E5%8E%9F%E7%90%86%E5%9B%BE"><span class="toc-text">2、主从同步的原理图</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3%E3%80%81%E4%B8%BB%E4%BB%8E%E5%90%8C%E6%AD%A5%E7%9A%84%E6%B5%81%E7%A8%8B"><span class="toc-text">3、主从同步的流程</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BA%8C%E3%80%81%E5%8D%8A%E5%90%8C%E6%AD%A5%E5%8E%9F%E7%90%86"><span class="toc-text">二、半同步原理</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%E3%80%81%E5%8D%8A%E5%90%8C%E6%AD%A5%E6%B5%81%E7%A8%8B"><span class="toc-text">1、半同步流程</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%E3%80%81%E5%8D%8A%E5%90%8C%E6%AD%A5%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">2、半同步应用场景</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%89%E3%80%81%E5%BC%82%E6%AD%A5%E5%A4%8D%E5%88%B6%E5%92%8C%E5%8D%8A%E5%90%8C%E6%AD%A5%E5%8C%BA%E5%88%AB"><span class="toc-text">三、异步复制和半同步区别</span></a></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/2022/03/06/Mysql%E7%9A%84%E4%BC%98%E5%8C%96-%E8%87%AA%E6%88%91%E6%8F%8F%E8%BF%B0/" title="MySQL 的优化.md"><img data-lazy-src="https://img2.baidu.com/it/u=1814268193,3619863984&amp;fm=253&amp;fmt=auto&amp;app=138&amp;f=JPEG?w=632&amp;h=500" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="MySQL 的优化.md"/></a><div class="content"><a class="title" href="/2022/03/06/Mysql%E7%9A%84%E4%BC%98%E5%8C%96-%E8%87%AA%E6%88%91%E6%8F%8F%E8%BF%B0/" title="MySQL 的优化.md">MySQL 的优化.md</a><time datetime="2022-03-06T14:54:18.000Z" title="发表于 2022-03-06 22:54:18">2022-03-06</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2022/03/06/MySQL%E6%95%B0%E6%8D%AE%E5%BA%93%E5%A4%87%E4%BB%BD%E5%91%BD%E4%BB%A4-20210722/" title="MySQL 数据库备份命令.md"><img data-lazy-src="https://img2.baidu.com/it/u=1814268193,3619863984&amp;fm=253&amp;fmt=auto&amp;app=138&amp;f=JPEG?w=632&amp;h=500" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="MySQL 数据库备份命令.md"/></a><div class="content"><a class="title" href="/2022/03/06/MySQL%E6%95%B0%E6%8D%AE%E5%BA%93%E5%A4%87%E4%BB%BD%E5%91%BD%E4%BB%A4-20210722/" title="MySQL 数据库备份命令.md">MySQL 数据库备份命令.md</a><time datetime="2022-03-06T14:47:18.000Z" title="发表于 2022-03-06 22:47:18">2022-03-06</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2022/03/06/Git-study/" title="git 笔记.md"><img data-lazy-src="https://gitee.com/forkiller/picture/raw/master/img/20220306225241.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="git 笔记.md"/></a><div class="content"><a class="title" href="/2022/03/06/Git-study/" title="git 笔记.md">git 笔记.md</a><time datetime="2022-03-06T14:47:18.000Z" title="发表于 2022-03-06 22:47:18">2022-03-06</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2022/03/06/Junit&amp;jdk8%E6%96%B0%E7%89%B9%E6%80%A7/" title="jdk8 新特性.md"><img data-lazy-src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.05sun.com%2Fup%2F2006%2F2020611101156542640.png&amp;refer=http%3A%2F%2Fimg.05sun.com&amp;app=2002&amp;size=f9999,10000&amp;q=a80&amp;n=0&amp;g=0n&amp;fmt=jpeg?sec=1649170568&amp;t=1d3529a6cb00dac37673cce4473d9a89" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="jdk8 新特性.md"/></a><div class="content"><a class="title" href="/2022/03/06/Junit&amp;jdk8%E6%96%B0%E7%89%B9%E6%80%A7/" title="jdk8 新特性.md">jdk8 新特性.md</a><time datetime="2022-03-06T14:47:18.000Z" title="发表于 2022-03-06 22:47:18">2022-03-06</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2022/03/06/Docker%20%E7%AC%94%E8%AE%B0_20210404/" title="Docker 笔记.md"><img data-lazy-src="https://gitee.com/forkiller/picture/raw/master/img/20220306223850.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Docker 笔记.md"/></a><div class="content"><a class="title" href="/2022/03/06/Docker%20%E7%AC%94%E8%AE%B0_20210404/" title="Docker 笔记.md">Docker 笔记.md</a><time datetime="2022-03-06T14:29:58.000Z" title="发表于 2022-03-06 22:29:58">2022-03-06</time></div></div></div></div></div></div></main><footer id="footer" style="background-image: url('https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg')"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2022 By Steve</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="font-plus" type="button" title="放大字体"><i class="fas fa-plus"></i></button><button id="font-minus" type="button" title="缩小字体"><i class="fas fa-minus"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><div class="search-dialog__title" id="local-search-title">本地搜索</div><div id="local-input-panel"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div></div><hr/><div id="local-search-results"></div><span class="search-close-button"><i class="fas fa-times"></i></span></div><div id="search-mask"></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/medium-zoom/dist/medium-zoom.min.js"></script><script src="https://cdn.jsdelivr.net/npm/instant.page/instantpage.min.js" type="module"></script><script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload/dist/lazyload.iife.min.js"></script><script>function panguFn () {
  if (typeof pangu === 'object') pangu.autoSpacingPage()
  else {
    getScript('https://cdn.jsdelivr.net/npm/pangu/dist/browser/pangu.min.js')
      .then(() => {
        pangu.autoSpacingPage()
      })
  }
}

function panguInit () {
  if (false){
    GLOBAL_CONFIG_SITE.isPost && panguFn()
  } else {
    panguFn()
  }
}

document.addEventListener('DOMContentLoaded', panguInit)</script><script src="/js/search/local-search.js"></script><div class="js-pjax"></div><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/activate-power-mode.min.js"></script><script>POWERMODE.colorful = true;
POWERMODE.shake = true;
POWERMODE.mobile = true;
document.body.addEventListener('input', POWERMODE);
</script><script id="click-heart" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/click-heart.min.js" async="async" mobile="true"></script><script src="https://cdn.jsdelivr.net/npm/pjax/pjax.min.js"></script><script>let pjaxSelectors = [
  'title',
  '#config-diff',
  '#body-wrap',
  '#rightside-config-hide',
  '#rightside-config-show',
  '.js-pjax'
]

if (false) {
  pjaxSelectors.unshift('meta[property="og:image"]', 'meta[property="og:title"]', 'meta[property="og:url"]')
}

var pjax = new Pjax({
  elements: 'a:not([target="_blank"])',
  selectors: pjaxSelectors,
  cacheBust: false,
  analytics: false,
  scrollRestoration: false
})

document.addEventListener('pjax:complete', function () {
  window.refreshFn()

  document.querySelectorAll('script[data-pjax]').forEach(item => {
    const newScript = document.createElement('script')
    const content = item.text || item.textContent || item.innerHTML || ""
    Array.from(item.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value))
    newScript.appendChild(document.createTextNode(content))
    item.parentNode.replaceChild(newScript, item)
  })

  GLOBAL_CONFIG.islazyload && window.lazyLoadInstance.update()

  typeof chatBtnFn === 'function' && chatBtnFn()
  typeof panguInit === 'function' && panguInit()

  if (typeof gtag === 'function') {
    gtag('config', '', {'page_path': window.location.pathname});
  }

  typeof loadMeting === 'function' && document.getElementsByClassName('aplayer').length && loadMeting()

  // Analytics
  if (false) {
    MtaH5.pgv()
  }

  // prismjs
  typeof Prism === 'object' && Prism.highlightAll()

  typeof preloader === 'object' && preloader.endLoading()
})


document.addEventListener('pjax:send', function () {
  typeof preloader === 'object' && preloader.initLoading()
  
  if (window.aplayers) {
    for (let i = 0; i < window.aplayers.length; i++) {
      if (!window.aplayers[i].options.fixed) {
        window.aplayers[i].destroy()
      }
    }
  }

  typeof typed === 'object' && typed.destroy()

  //reset readmode
  const $bodyClassList = document.body.classList
  $bodyClassList.contains('read-mode') && $bodyClassList.remove('read-mode')

})

document.addEventListener('pjax:error', (e) => {
  if (e.request.status === 404) {
    pjax.loadUrl('/404.html')
  }
})</script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>